{"record":{"id":"8730aebbe36bcdba","repo":"alibaba/spring-ai-alibaba","slug":"tool-message-not-supported","errorCode":null,"errorMessage":"Tool message not supported","messagePattern":"Tool message not supported","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/generator/workflow/sections/LLMNodeSection.java","lineNumber":71,"sourceCode":"\t\t\t\tObjectToCodeUtil.toCode(nodeData.getDefaultOutput()),\n\t\t\t\tObjectToCodeUtil.toCode(nodeData.getErrorNextNode()),\n\t\t\t\tObjectToCodeUtil.toCode(nodeData.getOutputKeyPrefix()));\n\t}\n\n\t@Override\n\tpublic String assistMethodCode(DSLDialectType dialectType) {\n\n\t\treturn String.format(\n\t\t\t\t\"\"\"\n\t\t\t\t\t\tprivate record MessageTemplate(String template, List<String> keys, MessageType type) {\n\t\t\t\t\t\t    public Message render(OverAllState state) {\n\t\t\t\t\t\t        Map<String, Object> params = keys.stream()\n\t\t\t\t\t\t            .collect(Collectors.toMap(key -> key, key -> state.value(key, \"\"), (o1, o2) -> o2));\n\t\t\t\t\t\t        String text = new PromptTemplate(template).render(params);\n\t\t\t\t\t\t        return switch (type) {\n\t\t\t\t\t\t            case USER -> new UserMessage(text);\n\t\t\t\t\t\t            case SYSTEM -> new SystemMessage(text);\n\t\t\t\t\t\t            case TOOL -> throw new UnsupportedOperationException(\"Tool message not supported\");\n\t\t\t\t\t\t            case ASSISTANT -> new AssistantMessage(text);\n\t\t\t\t\t\t        };\n\t\t\t\t\t\t    }\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprivate NodeAction createLLMNodeAction(ChatModel chatModel,\n\t\t\t\t\t\t        String chatModelName, Map<String, Number> modeParams,\n\t\t\t\t\t\t        List<MessageTemplate> messageTemplates, String memoryKey, Integer maxRetryCount, Integer retryIntervalMs,\n\t\t\t\t\t\t        String defaultOutput, String errorNextNode, String outputKeyPrefix) {\n\t\t\t\t\t\t    // build chatClient with params\n\t\t\t\t\t\t    var chatOptionsBuilder = DashScopeChatOptions.builder().withModel(chatModelName);\n\t\t\t\t\t\t    Optional.ofNullable(modeParams.get(\"temperature\")).ifPresent(val -> chatOptionsBuilder.withTemperature(val.doubleValue()));\n\t\t\t\t\t\t    Optional.ofNullable(modeParams.get(\"seed\")).ifPresent(val -> chatOptionsBuilder.withSeed(val.intValue()));\n\t\t\t\t\t\t    Optional.ofNullable(modeParams.get(\"top_p\")).ifPresent(val -> chatOptionsBuilder.withTopP(val.doubleValue()));\n\t\t\t\t\t\t    Optional.ofNullable(modeParams.get(\"top_k\")).ifPresent(val -> chatOptionsBuilder.withTopK(val.intValue()));\n\t\t\t\t\t\t    Optional.ofNullable(modeParams.get(\"max_tokens\")).ifPresent(val -> chatOptionsBuilder.withMaxToken(val.intValue()));\n\t\t\t\t\t\t    Optional.ofNullable(modeParams.get(\"repetition_penalty\")).ifPresent(val -> chatOptionsBuilder.withRepetitionPenalty(val.doubleValue()));\n\t\t\t\t\t\t    final ChatClient chatClient = ChatClient.builder(chatModel).defaultOptions(chatOptionsBuilder.build()).build();","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/generator/workflow/sections/LLMNodeSection.java#L53-L89","documentation":"LLMNodeSection.assistMethodCode generates code that maps message template types to Spring AI Message objects. TOOL messages are not supported by the generated LLM node, so the generated switch throws UnsupportedOperationException if a TOOL-typed message template appears.","triggerScenarios":"An LLM node's message templates in the DSL include an entry with type TOOL, and the generated method executes at runtime with state values.","commonSituations":"Dify DSL imports where the LLM node contains tool/context message entries; manually authored DSLs copying tool message roles; DSL upgrades adding new message roles the generator does not handle.","solutions":["Remove TOOL-typed message templates from the LLM node's message list in the DSL","Change the template type to USER, SYSTEM, or ASSISTANT","Add TOOL handling in the generated switch in LLMNodeSection if tool messages must be supported"],"exampleFix":"// before\n{\"messages\": [{\"type\": \"TOOL\", \"template\": \"...\"}]}\n// after\n{\"messages\": [{\"type\": \"USER\", \"template\": \"...\"}]}","handlingStrategy":"validation","validationCode":"boolean hasToolMessages = nodeData.getMessages().stream().anyMatch(m -> m.getType() == MessageType.TOOL); if (hasToolMessages) { throw new IllegalArgumentException(\"LLM node must not contain TOOL message templates\"); }","typeGuard":"boolean isGeneratableMessage(MessageTemplate m) { return EnumSet.of(MessageType.USER, MessageType.SYSTEM, MessageType.ASSISTANT).contains(m.getType()); }","tryCatchPattern":"try { runGeneratedFlow(...); } catch (UnsupportedOperationException e) { /* TOOL message encountered at runtime */ }","preventionTips":["Strip tool/context messages when importing Dify LLM nodes","Restrict message type options in the Studio UI for LLM nodes","Add TOOL support to the generator if needed before allowing such DSLs"],"tags":["java","spring-ai","codegen","unsupported"],"backgroundTag":"unsupported-enum-value","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"}