{"record":{"id":"bf0360702d592d81","repo":"alibaba/spring-ai-alibaba","slug":"currently-spring-ai-toolresponsemessage-only-suppo","errorCode":null,"errorMessage":"Currently Spring AI ToolResponseMessage only supports text type, that's why the return type of this method is String. More types like image/audio/video/file can be supported in the future.","messagePattern":"Currently Spring AI ToolResponseMessage only supports text type, that's why the return type of this method is String\\. More types like image/audio/video/file can be supported in the future\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/MessageToolCallResultConverter.java","lineNumber":47,"sourceCode":"import org.slf4j.LoggerFactory;\n\npublic class MessageToolCallResultConverter implements ToolCallResultConverter {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(MessageToolCallResultConverter.class);\n\n\t/**\n\t * Currently Spring AI ToolResponseMessage only supports text type, that's why the return type of this method is String.\n\t * More types like image/audio/video/file can be supported in the future.\n\t */\n\tpublic String convert(@Nullable Object result, @Nullable Type returnType) {\n\t\tif (returnType == Void.TYPE) {\n\t\t\tlogger.debug(\"The tool has no return type. Converting to conventional response.\");\n\t\t\treturn JsonParser.toJson(\"Done\");\n\t\t} else if (result instanceof AssistantMessage assistantMessage) {\n\t\t\tif (StringUtils.hasLength(assistantMessage.getText())) {\n\t\t\t\treturn assistantMessage.getText();\n\t\t\t} else if (CollectionUtils.isNotEmpty(assistantMessage.getMedia())) {\n\t\t\t\tthrow new UnsupportedOperationException(\"Currently Spring AI ToolResponseMessage only supports text type, that's why the return type of this method is String. More types like image/audio/video/file can be supported in the future.\");\n\t\t\t}\n\t\t\tlogger.warn(\"The tool returned an empty AssistantMessage. Converting to conventional response.\");\n\t\t\treturn JsonParser.toJson(\"Done\");\n\t\t} else {\n\t\t\tlogger.debug(\"Converting tool result to JSON.\");\n\t\t\treturn JsonParser.toJson(result);\n\t\t}\n\t}\n}\n","sourceCodeStart":29,"sourceCodeEnd":57,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/MessageToolCallResultConverter.java#L29-L57","documentation":"MessageToolCallResultConverter.convert throws UnsupportedOperationException when a tool returns an AssistantMessage that has media (image/audio/video/file) content but no text, because Spring AI's ToolResponseMessage only supports String (text) tool results.","triggerScenarios":"A @Tool method (or tool callback) returns an AssistantMessage whose media list is non-empty and whose text is empty; the converter then cannot produce a String result for the ToolResponseMessage.","commonSituations":"Wrapping a multimodal model output or generated image in an AssistantMessage and returning it from a tool; porting tools that returned richer content types from other frameworks.","solutions":["Return a String from the tool (e.g. a URL, base64, or textual description of the media) instead of a media-bearing AssistantMessage.","If returning AssistantMessage, ensure setText/description carries non-empty text alongside media.","Return a Map/POJO and let the converter JSON-serialize it instead of using AssistantMessage."],"exampleFix":"// before\nreturn new AssistantMessage(\"\", List.of(new Media(MimeTypeUtils.IMAGE_PNG, url)));\n// after\nreturn \"Generated image available at \" + url;","handlingStrategy":"type-guard","validationCode":"if (result instanceof AssistantMessage am && !am.hasText() && CollectionUtils.isNotEmpty(am.getMedia())) {\n    throw new IllegalStateException(\"Tool returns media-only AssistantMessage; return a String instead\");\n}","typeGuard":"static boolean isTextOnlyResult(Object r) {\n    return !(r instanceof AssistantMessage am) || (StringUtils.hasLength(am.getText()) || CollectionUtils.isEmpty(am.getMedia()));\n}","tryCatchPattern":"try { result = tool.call(args, ctx); } catch (UnsupportedOperationException e) { result = describeMediaAsText(toolResult); }","preventionTips":["Have tools return String or simple POJOs, not AssistantMessage with media.","Document that Spring AI tool results are text-only in this converter.","Wrap media outputs as URLs or descriptions in the tool itself."],"tags":["multimodal","unsupported-operation","tool-result"],"backgroundTag":"unsupported-operation","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}