{"record":{"id":"115d393938d8bd41","repo":"spring-projects/spring-ai","slug":"conversion-from-json-failed","errorCode":null,"errorMessage":"Conversion from JSON failed","messagePattern":"Conversion from JSON failed","errorType":"exception","errorClass":"ToolExecutionException","httpStatus":null,"severity":"error","filePath":"spring-ai-model/src/main/java/org/springframework/ai/tool/method/MethodToolCallback.java","lineNumber":140,"sourceCode":"\t\treturn this.toolCallResultConverter.convert(result, returnType);\n\t}\n\n\tprivate void validateToolContextSupport(@Nullable ToolContext toolContext) {\n\t\tvar isNonEmptyToolContextProvided = toolContext != null && !CollectionUtils.isEmpty(toolContext.getContext());\n\t\tvar isToolContextAcceptedByMethod = Stream.of(this.toolMethod.getParameterTypes())\n\t\t\t.anyMatch(type -> ClassUtils.isAssignable(ToolContext.class, type));\n\t\tif (isToolContextAcceptedByMethod && !isNonEmptyToolContextProvided) {\n\t\t\tthrow new IllegalArgumentException(\"ToolContext is required by the method as an argument\");\n\t\t}\n\t}\n\n\tprivate @Nullable Map<String, Object> extractToolArguments(String toolInput) {\n\t\ttry {\n\t\t\treturn jsonHelper.fromJson(toolInput, new ParameterizedTypeReference<>() {\n\t\t\t});\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.warn(\"Conversion from JSON failed\", ex);\n\t\t\tThrowable cause = (ex.getCause() instanceof JacksonException) ? ex.getCause() : ex;\n\t\t\tthrow new ToolExecutionException(this.getToolDefinition(), cause);\n\t\t}\n\t}\n\n\t// Based on the implementation in MethodToolCallback.\n\t@SuppressWarnings(\"null\")\n\tprivate Object[] buildMethodArguments(Map<String, Object> toolInputArguments, @Nullable ToolContext toolContext) {\n\t\treturn Stream.of(this.toolMethod.getParameters()).map(parameter -> {\n\t\t\tif (ClassUtils.isAssignable(ToolContext.class, parameter.getType())) {\n\t\t\t\treturn toolContext;\n\t\t\t}\n\t\t\tObject rawArgument = toolInputArguments.get(parameter.getName());\n\t\t\treturn buildTypedArgument(rawArgument, parameter.getParameterizedType());\n\t\t}).toArray();\n\t}\n\n\tprivate @Nullable Object buildTypedArgument(@Nullable Object value, Type type) {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/tool/method/MethodToolCallback.java#L122-L158","documentation":"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.","triggerScenarios":"toolArguments -> extractToolArguments when jsonHelper.fromJson(toolInput, Map) throws (invalid JSON syntax, wrong root shape).","commonSituations":"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.","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."],"exampleFix":"// before — no handling, error propagates\nString result = chatClient.prompt().tools(myTool).call().content();\n\n// after\ntry {\n    String result = chatClient.prompt().tools(myTool).call().content();\n} catch (ToolExecutionException e) {\n    logger.warn(\"Model produced invalid tool arguments, retrying\", e);\n    result = retryOnce();\n}","handlingStrategy":"try-catch","validationCode":"// validate model output before trusting it\nif (rawArgs != null && !rawArgs.trim().startsWith(\"{\")) {\n    logger.warn(\"Model returned non-object tool arguments: {}\", rawArgs);\n}","typeGuard":"boolean isJsonObject(String s) {\n    if (s == null) return false;\n    try { new ObjectMapper().readTree(s); return true; } catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n    return chatClient.prompt().tools(myTool).call().content();\n} catch (ToolExecutionException e) {\n    logger.warn(\"Invalid tool arguments from model, retrying\", e);\n    return chatClient.prompt().tools(myTool).call().content(); // retry once\n}","preventionTips":["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."],"tags":["tool-calling","json","deserialization"],"backgroundTag":"json-parse-error","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}