{"record":{"id":"4eea30fba4e9bb1a","repo":"alibaba/spring-ai-alibaba","slug":"the-tool-returned-an-empty-assistantmessage-conve","errorCode":null,"errorMessage":"The tool returned an empty AssistantMessage. Converting to conventional response.","messagePattern":"The tool returned an empty AssistantMessage\\. Converting to conventional response\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/MessageToolCallResultConverter.java","lineNumber":49,"sourceCode":"public 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":31,"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#L31-L57","documentation":"MessageToolCallResultConverter converts a tool's return value into a string for ToolResponseMessage. An AssistantMessage with empty text (and no media) carries no usable content, so the converter logs this warning and returns the conventional JSON '\"Done\"' response.","triggerScenarios":"A @Tool-annotated method (or ToolCallback) returns an AssistantMessage whose getText() is empty/blank and getMedia() is empty, e.g. new AssistantMessage(\"\").","commonSituations":"Tool wraps an LLM call that returned empty content; tool builds AssistantMessage programmatically with null/blank text; upstream model outage yields empty message passed through as tool result.","solutions":["Return a non-empty string or ToolResponseMessage from the tool instead of an empty AssistantMessage","Check text before constructing AssistantMessage and fall back to a meaningful placeholder","Handle media separately — media in AssistantMessage throws UnsupportedOperationException here","Log/inspect the tool pipeline to find why the wrapped generation returned empty text"],"exampleFix":"// before\nreturn new AssistantMessage(\"\"); // warns, becomes \"Done\"\n// after\nString text = generate();\nreturn new AssistantMessage(text != null && !text.isBlank() ? text : \"No content generated\");","handlingStrategy":"validation","validationCode":"if (toolResult instanceof AssistantMessage am && (am.getText() == null || am.getText().isBlank()) && (am.getMedia() == null || am.getMedia().isEmpty())) { log.warn(\"Tool produced empty AssistantMessage\"); }","typeGuard":"static boolean hasUsableText(AssistantMessage m) { return m != null && m.getText() != null && !m.getText().isBlank(); }","tryCatchPattern":null,"preventionTips":["Return plain Strings or ToolResponseMessage from tools rather than raw AssistantMessage","Validate LLM output for emptiness inside tools before wrapping","Never put media in AssistantMessage returned to this converter (it throws UnsupportedOperationException)"],"tags":["tool-result","empty-message","assistantmessage"],"backgroundTag":"empty-required-field","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}