alibaba/spring-ai-alibaba · error · IllegalArgumentException
ReactAgent requires model configuration in handle
Error message
ReactAgent requires model configuration in handle
What it means
ReactAgentProvider.validateSpecific() throws this when a react_agent's "handle" section has no "model" entry. A ReactAgent needs an LLM to run its reasoning loop, so the model configuration is mandatory. The DSL passes structural validation but is semantically incomplete for generation.
Solutions
- Add a "model" entry inside the "handle" object of the react_agent config
- Ensure the selected model is available in the target environment (e.g. a DashScope model name)
- If the agent is meant to be model-less, use a non-React agent type (e.g. a plain workflow node)
Example fix
// before
{"type": "react_agent", "name": "assistant", "handle": {"tools": ["search"]}}
// after
{"type": "react_agent", "name": "assistant", "handle": {"model": "qwen-max", "tools": ["search"]}} Defensive patterns
Strategy: validation
Validate before calling
Map<String,Object> handle = (Map<String,Object>) config.get("handle");
if (handle == null || handle.get("model") == null) {
throw new IllegalArgumentException("react_agent handle requires a 'model' entry");
} Type guard
static boolean hasModel(Map<String,Object> cfg) {
return cfg.get("handle") instanceof Map<?,?> h && h.get("model") != null;
} Try / catch
try {
provider.validateDSL(root);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("requires model configuration")) {
// prompt user to pick a model for the react_agent
}
} Prevention
- Always set handle.model for react_agent definitions
- Validate model availability in the target environment (API keys, model names)
- Configure a default model in your UI/exporter so the field is never dropped
- Use a model-less agent type for pure tool/workflow nodes
When it happens
Trigger: validateDSL calls validateSpecific(root); requireHandle(root) succeeds but handle.get("model") == null — the handle section omits the model key entirely.
Common situations: Copying a tool-only or workflow sub-agent config into a react_agent; a UI export that strips the model when no default model is selected; deleting a model reference that pointed to an unavailable model.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- must be a number
- invalid agent dsl: missing 'agent' object or flat agent…
- invalid agent dsl: 'type/agent_class' and 'name' are…
- invalid dify dsl
- invalid dsl
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/e5e5c6367aef4c46.
Report an issue: GitHub.
Appendix: 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/agent/impl/ReactAgentProvider.java:165
"import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;",
"import org.springframework.ai.chat.model.ChatModel;",
"import org.springframework.context.annotation.Bean;",
"import org.springframework.stereotype.Component;",
hasResolver ? "import org.springframework.beans.factory.ObjectProvider;" : null,
hasResolver ? "import org.springframework.ai.tool.resolution.ToolCallbackResolver;" : null,
"import java.util.*;")
.code(code.toString())
.var(var)
.resolver(hasResolver);
}
@Override
protected void validateSpecific(Map<String, Object> root) {
// ReactAgent 必须有 model 配置
Map<String, Object> handle = requireHandle(root);
if (handle.get("model") == null) {
throw new IllegalArgumentException("ReactAgent requires model configuration in handle");
}
// 如果有 tools,检查相关配置
if (handle.get("tools") instanceof List<?> tools && !tools.isEmpty()) {
// 检查 tools 是否为空字符串
for (Object tool : tools) {
if (tool instanceof String s && s.trim().isEmpty()) {
throw new IllegalArgumentException("ReactAgent tool names cannot be empty");
}
}
}
// 检查 max_iterations 如果存在,必须是正数
Object maxIterations = handle.get("max_iterations");
if (maxIterations != null) {
requirePositiveNumber(maxIterations, "max_iterations", 1);
}
}View on GitHub (pinned to f82da0b50f)