alibaba/spring-ai-alibaba · error · UnsupportedOperationException
Tool message not supported
Error message
Tool message not supported
What it means
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.
Source
Thrown at 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:71
ObjectToCodeUtil.toCode(nodeData.getDefaultOutput()),
ObjectToCodeUtil.toCode(nodeData.getErrorNextNode()),
ObjectToCodeUtil.toCode(nodeData.getOutputKeyPrefix()));
}
@Override
public String assistMethodCode(DSLDialectType dialectType) {
return String.format(
"""
private record MessageTemplate(String template, List<String> keys, MessageType type) {
public Message render(OverAllState state) {
Map<String, Object> params = keys.stream()
.collect(Collectors.toMap(key -> key, key -> state.value(key, ""), (o1, o2) -> o2));
String text = new PromptTemplate(template).render(params);
return switch (type) {
case USER -> new UserMessage(text);
case SYSTEM -> new SystemMessage(text);
case TOOL -> throw new UnsupportedOperationException("Tool message not supported");
case ASSISTANT -> new AssistantMessage(text);
};
}
}
private NodeAction createLLMNodeAction(ChatModel chatModel,
String chatModelName, Map<String, Number> modeParams,
List<MessageTemplate> messageTemplates, String memoryKey, Integer maxRetryCount, Integer retryIntervalMs,
String defaultOutput, String errorNextNode, String outputKeyPrefix) {
// build chatClient with params
var chatOptionsBuilder = DashScopeChatOptions.builder().withModel(chatModelName);
Optional.ofNullable(modeParams.get("temperature")).ifPresent(val -> chatOptionsBuilder.withTemperature(val.doubleValue()));
Optional.ofNullable(modeParams.get("seed")).ifPresent(val -> chatOptionsBuilder.withSeed(val.intValue()));
Optional.ofNullable(modeParams.get("top_p")).ifPresent(val -> chatOptionsBuilder.withTopP(val.doubleValue()));
Optional.ofNullable(modeParams.get("top_k")).ifPresent(val -> chatOptionsBuilder.withTopK(val.intValue()));
Optional.ofNullable(modeParams.get("max_tokens")).ifPresent(val -> chatOptionsBuilder.withMaxToken(val.intValue()));
Optional.ofNullable(modeParams.get("repetition_penalty")).ifPresent(val -> chatOptionsBuilder.withRepetitionPenalty(val.doubleValue()));
final ChatClient chatClient = ChatClient.builder(chatModel).defaultOptions(chatOptionsBuilder.build()).build();View on GitHub (pinned to f82da0b50f)
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
Example fix
// before
{"messages": [{"type": "TOOL", "template": "..."}]}
// after
{"messages": [{"type": "USER", "template": "..."}]} Defensive patterns
Strategy: validation
Validate before calling
boolean hasToolMessages = nodeData.getMessages().stream().anyMatch(m -> m.getType() == MessageType.TOOL); if (hasToolMessages) { throw new IllegalArgumentException("LLM node must not contain TOOL message templates"); } Type guard
boolean isGeneratableMessage(MessageTemplate m) { return EnumSet.of(MessageType.USER, MessageType.SYSTEM, MessageType.ASSISTANT).contains(m.getType()); } Try / catch
try { runGeneratedFlow(...); } catch (UnsupportedOperationException e) { /* TOOL message encountered at runtime */ } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unsupported document type: ${documentType}
- ChatClient error
- AppTypeNotSupport
- unsupported format:
- Elastic search index name must be provided
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/8730aebbe36bcdba.
Report an issue: GitHub.