spring-projects/spring-ai · error · ToolExecutionException
Conversion from JSON failed
Error message
Conversion from JSON failed
What it means
MethodToolCallback.extractToolArguments fails to deserialize the LLM-provided tool input JSON into the arguments map and throws ToolExecutionException wrapping the cause. This means the JSON emitted by the model is malformed or not an object. The warning "Conversion from JSON failed" is logged with the full exception before throwing.
Source
Thrown at spring-ai-model/src/main/java/org/springframework/ai/tool/method/MethodToolCallback.java:140
return this.toolCallResultConverter.convert(result, returnType);
}
private void validateToolContextSupport(@Nullable ToolContext toolContext) {
var isNonEmptyToolContextProvided = toolContext != null && !CollectionUtils.isEmpty(toolContext.getContext());
var isToolContextAcceptedByMethod = Stream.of(this.toolMethod.getParameterTypes())
.anyMatch(type -> ClassUtils.isAssignable(ToolContext.class, type));
if (isToolContextAcceptedByMethod && !isNonEmptyToolContextProvided) {
throw new IllegalArgumentException("ToolContext is required by the method as an argument");
}
}
private @Nullable Map<String, Object> extractToolArguments(String toolInput) {
try {
return jsonHelper.fromJson(toolInput, new ParameterizedTypeReference<>() {
});
}
catch (Exception ex) {
logger.warn("Conversion from JSON failed", ex);
Throwable cause = (ex.getCause() instanceof JacksonException) ? ex.getCause() : ex;
throw new ToolExecutionException(this.getToolDefinition(), cause);
}
}
// Based on the implementation in MethodToolCallback.
@SuppressWarnings("null")
private Object[] buildMethodArguments(Map<String, Object> toolInputArguments, @Nullable ToolContext toolContext) {
return Stream.of(this.toolMethod.getParameters()).map(parameter -> {
if (ClassUtils.isAssignable(ToolContext.class, parameter.getType())) {
return toolContext;
}
Object rawArgument = toolInputArguments.get(parameter.getName());
return buildTypedArgument(rawArgument, parameter.getParameterizedType());
}).toArray();
}
private @Nullable Object buildTypedArgument(@Nullable Object value, Type type) {View on GitHub (pinned to 98a7beda4f)
Solutions
- Inspect the raw toolInput string logged with the warning; fix the model prompt or model choice to emit valid JSON object arguments.
- Enable strict JSON/tool mode on the provider if available (e.g. OpenAI tool_call arguments).
- If streaming, ensure argument chunks are concatenated completely before execution.
- Catch ToolExecutionException around the ChatClient call and retry the request.
Example fix
// before — no handling, error propagates
String result = chatClient.prompt().tools(myTool).call().content();
// after
try {
String result = chatClient.prompt().tools(myTool).call().content();
} catch (ToolExecutionException e) {
logger.warn("Model produced invalid tool arguments, retrying", e);
result = retryOnce();
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate model output before trusting it
if (rawArgs != null && !rawArgs.trim().startsWith("{")) {
logger.warn("Model returned non-object tool arguments: {}", rawArgs);
} Type guard
boolean isJsonObject(String s) {
if (s == null) return false;
try { new ObjectMapper().readTree(s); return true; } catch (Exception e) { return false; }
} Try / catch
try {
return chatClient.prompt().tools(myTool).call().content();
} catch (ToolExecutionException e) {
logger.warn("Invalid tool arguments from model, retrying", e);
return chatClient.prompt().tools(myTool).call().content(); // retry once
} Prevention
- Catch ToolExecutionException around ChatClient calls.
- Use models supporting strict/structured tool-call JSON.
- Avoid streaming for tools with complex arguments.
- Validate JSON payload in integration tests with a stubbed model.
When it happens
Trigger: toolArguments -> extractToolArguments when jsonHelper.fromJson(toolInput, Map) throws (invalid JSON syntax, wrong root shape).
Common situations: LLM emits truncated or unquoted JSON in tool arguments; model returns a JSON array or string instead of an object; streaming aggregation lost part of the arguments payload.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- Unexpected JSON token %s within the array!
- Unexpected JSON token %s!
- Cannot deserialize ThinkOption from token:
- Conversion from JSON to %s failed
- Conversion from JSON to %s failed
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/115d393938d8bd41.
Report an issue: GitHub.