alibaba/spring-ai-alibaba · error · IllegalArgumentException
Either 'instruction' or 'includeContents' must be set for…
Error message
Either 'instruction' or 'includeContents' must be set for Agent.
What it means
AgentLlmNode.apply() builds the message list for the LLM call. If the graph state has no "messages" key and also no "input" key, there is nothing to send to the model, so it throws IllegalArgumentException telling you to configure an instruction or include contents.
Solutions
- Set an instruction on the Agent builder so the node has a prompt
- Include contents / seed the state with at least one Message
- Pass input under the "input" key when using the agent as a plain graph node
- Pass input as {"messages": [new UserMessage("...")]} to match the expected state key
Example fix
// before
OverAllState input = new OverAllState(Map.of("query", "hello")); // no 'messages'/'input'
// after
OverAllState input = new OverAllState(Map.of("input", "hello"));
// or: Map.of("messages", List.of(new UserMessage("hello"))) Defensive patterns
Strategy: try-catch
Validate before calling
boolean agentInputValid(Map<String,Object> state) { return state.containsKey("messages") || state.containsKey("input"); } Type guard
boolean hasMessages(OverAllState s) { return s.value("messages").isPresent() || s.value("input").isPresent(); } Try / catch
try { node.apply(state); } catch (IllegalArgumentException e) { log.error("Agent received no messages/input: {}", state.data()); throw e; } Prevention
- Always set an instruction on the Agent builder
- When using the agent as a graph node, pass input under the "input" or "messages" key
- Normalize upstream node outputs to the "messages" key
When it happens
Trigger: Invoking an agent (or graph using AgentLlmNode as a node) whose input state contains neither "messages" nor "input", e.g. passing an empty map or only non-message keys like "input_schema".
Common situations: Feeding a graph with structured input (JSON fields) instead of chat messages; forgetting to set the agent's instruction/prompt in the builder; upstream node failed to produce "messages"; renaming the input key in a custom node.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Cannot find AssistantMessage before ToolResponseMessage
- Cannot merge incompatible types
- Last message is neither an AssistantMessage nor a…
- Message before ToolResponseMessage is not an…
- ${message.getText()}
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/ab703a836952e426.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/node/AgentLlmNode.java:169
// Check and manage iteration counter
final AtomicInteger iterations;
if (!config.context().containsKey(MODEL_ITERATION_KEY)) {
iterations = new AtomicInteger(0);
config.context().put(MODEL_ITERATION_KEY, iterations);
} else {
iterations = (AtomicInteger) config.context().get(MODEL_ITERATION_KEY);
iterations.incrementAndGet();
}
// Check and manage messages
List<Message> messages = new ArrayList<>();
if (state.value("messages").isEmpty()) {
// try with "input" key, which is more commonly used in graph input when agent is used as a node.
if (state.value("input").isPresent()) {
messages.add(new UserMessage(state.value("input").get().toString()));
} else {
throw new IllegalArgumentException("Either 'instruction' or 'includeContents' must be set for Agent.");
}
} else {
messages = (List<Message>) state.value("messages").get();
}
augmentUserMessage(messages, outputSchema);
renderTemplatedUserMessage(messages, state.data(), config.metadata());
// Create ModelRequest; include state in context so interceptors (e.g. handoffs step-config) can read it
Map<String, Object> contextMap = new HashMap<>(state.data());
Map<String, Object> metadata = config.metadata().orElse(new HashMap<>());
if (!metadata.isEmpty()) {
contextMap.putAll(metadata);
}
ModelRequest.Builder requestBuilder = ModelRequest.builder()
.messages(messages)
.options(this.chatOptions != null ? this.chatOptions.copy() : null)
.context(contextMap);View on GitHub (pinned to f82da0b50f)