alibaba/spring-ai-alibaba · warning
No messages found in state when routing from model to tools
Error message
No messages found in state when routing from model to tools
What it means
ReactAgent's model-to-tools routing edge reads the 'messages' key from graph state to inspect the last message's tool calls. If the state has no messages at routing time, it logs this warning and routes to the END destination instead of the tools node, ending the run.
Solutions
- Ensure the model node stores its AssistantMessage under the standard 'messages' state key
- Do not set an outputKey on the ReactAgent that diverts messages away from 'messages' when tool routing is used
- Verify checkpoints/state include 'messages' when resuming
- Add a guard in custom graphs to initialize 'messages' before routing
Example fix
// before
node writes: state.set("model_output", assistantMessage); // 'messages' stays empty
// after
node appends: new AppendableValue<>("messages", assistantMessage); // routing sees the message Defensive patterns
Strategy: validation
Validate before calling
List<Message> messages = (List<Message>) state.value("messages").orElse(List.of());
if (messages.isEmpty()) { throw new IllegalStateException("'messages' state key must be populated before model-to-tools routing"); } Type guard
static boolean hasMessages(Map<String,Object> state) { Object m = state.get("messages"); return m instanceof List<?> l && !l.isEmpty(); } Prevention
- Keep the standard 'messages' key as the sole message channel when using ReactAgent tool routing
- Avoid setting outputKey on ReactAgents whose routing depends on 'messages'
- Test checkpoint/resume paths to confirm 'messages' round-trips through persistence
When it happens
Trigger: makeModelToTools routing function executes while state.value("messages") is empty — the model node produced no messages into state before the conditional edge was evaluated.
Common situations: Custom state graph replacing the default messages key; model node writing output to a different key (e.g. via outputKey) so 'messages' stays empty; state reducer misconfigured; resuming from a checkpoint that lacks messages.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- ReactAgent requires model configuration in handle
- Unsupported DTO type:
- Unsupported message type
- Unsupported message type:
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/cc6f78288611c699.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/ReactAgent.java:788
jumpTo = (JumpTo) jumpToValue;
} else if (jumpToValue instanceof String) {
jumpTo = JumpTo.fromStringOrNull((String) jumpToValue);
}
// If a valid jump_to instruction exists, execute it immediately
if (jumpTo != null) {
return switch (jumpTo) {
case model -> modelDestination;
case end -> endDestination;
case tool -> AGENT_TOOL_NAME;
};
}
}
// Priority 2: Check message content for tool calls
List<Message> messages = (List<Message>) state.value("messages").orElse(List.of());
if (messages.isEmpty()) {
logger.warn("No messages found in state when routing from model to tools");
return endDestination;
}
Message lastMessage = messages.get(messages.size() - 1);
// 1. Check the last message type
if (lastMessage instanceof AssistantMessage assistantMessage) {
// 2. If last message is AssistantMessage
if (assistantMessage.hasToolCalls()) {
return AGENT_TOOL_NAME;
} else {
return endDestination;
}
} else if (lastMessage instanceof ToolResponseMessage) {
// 3. If last message is ToolResponseMessage
if (messages.size() < 2) {
// Should not happen in a valid ReAct loop, but as a safeguard.
throw new RuntimeException("Less than 2 messages in state when last message is ToolResponseMessage");
}View on GitHub (pinned to f82da0b50f)