alibaba/spring-ai-alibaba · error · IllegalArgumentException
At least one limit must be specified (threadLimit or runLimi
Error message
At least one limit must be specified (threadLimit or runLimit)
What it means
ToolCallLimitHook.Builder.build() requires at least one of threadLimit or runLimit to be set. A hook with no limits would never restrict anything, so the builder rejects it as a configuration mistake.
Source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/hook/toolcalllimit/ToolCallLimitHook.java:216
public Builder threadLimit(Integer threadLimit) {
this.threadLimit = threadLimit;
return this;
}
public Builder runLimit(Integer runLimit) {
this.runLimit = runLimit;
return this;
}
public Builder exitBehavior(ExitBehavior exitBehavior) {
this.exitBehavior = exitBehavior;
return this;
}
public ToolCallLimitHook build() {
if (threadLimit == null && runLimit == null) {
throw new IllegalArgumentException("At least one limit must be specified (threadLimit or runLimit)");
}
return new ToolCallLimitHook(this);
}
}
}
View on GitHub (pinned to f82da0b50f)
Solutions
- Set at least one limit: .threadLimit(n) and/or .runLimit(m) before build().
- If you want only per-conversation caps use threadLimit; for per-run caps use runLimit; set both for combined enforcement.
- Skip constructing the hook entirely when no limiting is desired, instead of building one with no limits.
Example fix
// before ToolCallLimitHook hook = ToolCallLimitHook.builder().build(); // after ToolCallLimitHook hook = ToolCallLimitHook.builder().threadLimit(10).build();
Defensive patterns
Strategy: validation
Validate before calling
ToolCallLimitHook.Builder b = ToolCallLimitHook.builder();
// ensure at least one limit is set before build
if (threadLimit == null && runLimit == null) { throw new IllegalStateException("Set threadLimit or runLimit"); }
ToolCallLimitHook hook = b.threadLimit(threadLimit).build(); Type guard
boolean hasLimit(Integer threadLimit, Integer runLimit) { return threadLimit != null || runLimit != null; } Try / catch
try { hook = builder.build(); } catch (IllegalArgumentException e) { log.error("ToolCallLimitHook misconfigured: {}", e.getMessage()); } Prevention
- Never build a limit hook without setting at least one limit.
- Pick threadLimit for per-conversation caps, runLimit for per-run caps.
- If no limiting is wanted, do not register the hook at all.
When it happens
Trigger: Calling ToolCallLimitHook.builder().build() (or with only toolName/exitBehavior set) without ever calling .threadLimit(...) or .runLimit(...).
Common situations: Builder chain built dynamically where limit setters were skipped; copying a snippet and deleting the limit lines; assuming defaults exist (there are none).
Understand the failure class
Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.
Related errors
- SkillRegistry must be provided. Use FileSystemSkillRegistry.
- 参数 ${parameterName} 的值 ${value} 无法转换为类型 ${type}
- SubAgent name is required
- SubAgent description is required
- SubAgent system prompt is required
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/7e350e0b0f9440b2.
Report an issue: GitHub.