spring-projects/spring-ai · error · IllegalStateException
Currently only one tool call is supported per message!
Error message
Currently only one tool call is supported per message!
What it means
MistralAiStreamFunctionCallingHelper.merge() combines consecutive streaming chunks of a tool-calling response. It supports at most one tool call per streamed message; if an incoming chunk's toolCalls list contains more than one entry, IllegalStateException is thrown because incremental merging of multiple parallel tool calls is not implemented.
Source
Thrown at models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiStreamFunctionCallingHelper.java:131
private ChatCompletionMessage merge(ChatCompletionMessage previous, ChatCompletionMessage current) {
var content = (current.content() != null ? current.content()
: (previous.content() != null) ? previous.content() : "");
Role role = (current.role() != null ? current.role() : previous.role());
role = (role != null ? role : Role.ASSISTANT); // default to ASSISTANT (if null
String name = (current.name() != null ? current.name() : previous.name());
List<ToolCall> toolCalls = new ArrayList<>();
ToolCall lastPreviousTooCall = null;
if (previous.toolCalls() != null) {
lastPreviousTooCall = previous.toolCalls().get(previous.toolCalls().size() - 1);
if (previous.toolCalls().size() > 1) {
toolCalls.addAll(previous.toolCalls().subList(0, previous.toolCalls().size() - 1));
}
}
if (current.toolCalls() != null) {
if (current.toolCalls().size() > 1) {
throw new IllegalStateException("Currently only one tool call is supported per message!");
}
var currentToolCall = current.toolCalls().iterator().next();
if (currentToolCall.id() != null) {
if (lastPreviousTooCall != null) {
toolCalls.add(lastPreviousTooCall);
}
toolCalls.add(currentToolCall);
}
else {
toolCalls.add(merge(lastPreviousTooCall, currentToolCall));
}
}
else {
if (lastPreviousTooCall != null) {
toolCalls.add(lastPreviousTooCall);
}
}
return new ChatCompletionMessage(content, role, name, toolCalls);View on GitHub (pinned to 98a7beda4f)
Solutions
- Upgrade spring-ai-mistral-ai to a version supporting multiple parallel tool calls.
- Reduce exposed tools or adjust the prompt to discourage parallel tool calls.
- Handle tool calls non-streaming (use call() instead of stream()) where multi-tool-call responses are supported.
Defensive patterns
Strategy: try-catch
Validate before calling
long parallel = chunk.getChoices().stream()
.flatMap(c -> c.getMessage().getToolCalls() == null ? Stream.empty() : c.getMessage().getToolCalls().stream())
.count();
if (parallel > 1) { /* switch to non-streaming path */ } Try / catch
try {
return chatModel.stream(prompt);
} catch (IllegalStateException e) {
if (e.getMessage().contains("only one tool call")) { return chatModel.call(prompt); } // non-streaming fallback
throw e;
} Prevention
- Use the non-streaming call() path when prompts enable multiple tools that may be invoked in parallel.
- Upgrade to a Spring AI version with parallel tool-call streaming support.
- Instruct the model via system prompt to issue one tool call at a time when streaming.
When it happens
Trigger: Streaming a Mistral chat completion where the model emits a message with two or more parallel tool calls in one chunk (e.g. the model decides to call two functions simultaneously).
Common situations: Prompts that expose multiple tools to Mistral and the model responds with parallel tool invocation; newer Mistral models with multi tool-call output combined with an older Spring AI stream helper.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Streaming chat completion is not supported for this model:
- Currently only one tool call is supported per message!
- streaming is not supported
- Tool call arguments are null or empty for MCP tool: <toolNam
- Tool call arguments are null or empty for MCP tool: <toolNam
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/34d0206b64c6d061.
Report an issue: GitHub.