{"record":{"id":"c667965d25f4b0b4","repo":"spring-projects/spring-ai","slug":"failed-to-instantiate-toolcallresultconverter","errorCode":null,"errorMessage":"Failed to instantiate ToolCallResultConverter: ","messagePattern":"Failed to instantiate ToolCallResultConverter: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolUtils.java","lineNumber":102,"sourceCode":"\n\tpublic static boolean getToolReturnDirect(Method method) {\n\t\tAssert.notNull(method, \"method cannot be null\");\n\t\tvar tool = AnnotatedElementUtils.findMergedAnnotation(method, Tool.class);\n\t\treturn tool != null && tool.returnDirect();\n\t}\n\n\tpublic static ToolCallResultConverter getToolCallResultConverter(Method method) {\n\t\tAssert.notNull(method, \"method cannot be null\");\n\t\tvar tool = AnnotatedElementUtils.findMergedAnnotation(method, Tool.class);\n\t\tif (tool == null) {\n\t\t\treturn new DefaultToolCallResultConverter();\n\t\t}\n\t\tvar type = tool.resultConverter();\n\t\ttry {\n\t\t\treturn type.getDeclaredConstructor().newInstance();\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to instantiate ToolCallResultConverter: \" + type, e);\n\t\t}\n\t}\n\n\tpublic static List<String> getDuplicateToolNames(List<ToolCallback> toolCallbacks) {\n\t\tAssert.notNull(toolCallbacks, \"toolCallbacks cannot be null\");\n\t\treturn toolCallbacks.stream()\n\t\t\t.collect(Collectors.groupingBy(toolCallback -> toolCallback.getToolDefinition().name(),\n\t\t\t\t\tCollectors.counting()))\n\t\t\t.entrySet()\n\t\t\t.stream()\n\t\t\t.filter(entry -> entry.getValue() > 1)\n\t\t\t.map(Map.Entry::getKey)\n\t\t\t.toList();\n\t}\n\n\tpublic static List<String> getDuplicateToolNames(ToolCallback... toolCallbacks) {\n\t\tAssert.notNull(toolCallbacks, \"toolCallbacks cannot be null\");\n\t\treturn getDuplicateToolNames(Arrays.asList(toolCallbacks));","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolUtils.java#L84-L120","documentation":"Thrown when the ToolCallResultConverter class declared on a @Tool method's annotation cannot be instantiated: its no-arg constructor is missing or the newInstance call throws (abstract class, interface, constructor exception, inaccessible class).","triggerScenarios":"Setting ToolCallResultConverter.class in tool annotations/options to a class that (a) has no public no-arg constructor, (b) is abstract/an interface, (c) throws in its constructor, or (d) is not accessible from the caller's classloader/module.","commonSituations":"Writing a custom result converter with constructor arguments; passing a nested class without declaring it static; converter with initialization logic that fails (missing config); passing the annotation's default placeholder incorrectly.","solutions":["Give the converter class a public no-argument constructor","Ensure the converter is a concrete (non-abstract) static class","Remove or fix side effects in the constructor that can throw","Check class/module accessibility (public class, exported package, non-anonymous inner class)"],"exampleFix":"// before\nclass MyConverter {\n    MyConverter(ObjectMapper mapper) { ... }\n}\n// after\nclass MyConverter implements ToolCallResultConverter {\n    public MyConverter() { }\n    public String convert(@Nullable Object result, @Nullable Type returnType) { ... }\n}","handlingStrategy":"validation","validationCode":"try {\n    converterType.getDeclaredConstructor().newInstance();\n} catch (Exception e) {\n    throw new IllegalStateException(converterType + \" needs an accessible public no-arg constructor\", e);\n}","typeGuard":null,"tryCatchPattern":"try { tool.call(args); } catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Failed to instantiate ToolCallResultConverter\")) { /* fix converter class */ }\n}","preventionTips":["Write converters as public static classes with only a no-arg constructor","Unit-test converter instantiation for every custom ToolCallResultConverter","Keep constructor work minimal and non-throwing"],"tags":["spring-ai","reflection","instantiation"],"backgroundTag":"invalid-constructor-argument","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"}