Skip to content

ToolResponseMessage results in null content, causing SQLIntegrityConstraintViolationException in JdbcChatMemoryRepository #3339

Open
@astor-dev

Description

@astor-dev

Bug description
When a ChatResponse from the model includes a ToolCall (i.e., finishReason=TOOL_CALLS), the corresponding AssistantMessage has textContent = null.
When this message is added to the JdbcChatMemoryRepository, the implementation attempts to insert it into the database without null-checking the content field. This causes a SQL integrity error due to a NOT NULL constraint on the content column.

The ToolResponseMessage (or AssistantMessage with only toolCalls and no content) is not handled correctly in JdbcChatMemoryRepository. This leads to the following exception:

java.sql.SQLIntegrityConstraintViolationException: (conn=498) Column 'content' cannot be null

In contrast, the default in-memory implementation (MessageWindowChatMemory) tolerates null content and saving such messages with null textContent.

Environment

  • spring-ai 1.0.0
  • mariadb:10.11

Steps to reproduce

  1. Use a ChatModel that returns a response containing only toolCalls (e.g., OpenAI with function/tool calling).
  2. Capture that AssistantMessage and attempt to save it to JdbcChatMemoryRepository.
  3. Since textContent == null, the following SQL fails:
INSERT INTO SPRING_AI_CHAT_MEMORY (conversation_id, content, type, timestamp)
VALUES (?, NULL, 'ASSISTANT', ?)

.

Expected behavior
The repository should store the response with null value

Minimal Complete Reproducible example
Here is the code that caused the bug in my project.

fun call(conversationId: String, prompt: Prompt, toolCallingChatOption: ToolCallingChatOptions?): ChatResponse {
        val systemMessage = prompt.systemMessage
        chatMemory.add(conversationId, prompt.userMessage)
        val promptWithMemory = Prompt(chatMemory.get(conversationId) + prompt.systemMessage, toolCallingChatOption)
        var chatResponse = chatModel.call(promptWithMemory) ?: throw ErrorCode.CHAT_NULL_RESPONSE.toException()
        chatMemory.add(conversationId, chatResponse.result.output) // throw Exception
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions