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

  1. Inspect the raw toolInput string logged with the warning; fix the model prompt or model choice to emit valid JSON object arguments.
  2. Enable strict JSON/tool mode on the provider if available (e.g. OpenAI tool_call arguments).
  3. If streaming, ensure argument chunks are concatenated completely before execution.
  4. 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

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/115d393938d8bd41. Report an issue: GitHub.