alibaba/spring-ai-alibaba · error · IllegalStateException
ToolCallbackResolver is null; cannot resolve tool name:
Error message
ToolCallbackResolver is null; cannot resolve tool name:
What it means
DefaultBuilder.gatherLocalTools (reached via allTools) resolves tools registered only by name through the configured ToolCallbackResolver. If the resolver reference is null it throws IllegalStateException, since tool names cannot be turned into ToolCallback instances without it.
Solutions
- Set the resolver on the builder: .toolCallbackResolver(resolver) (e.g. the Spring ToolCallbackResolver bean).
- Register the tools as ToolCallback/MethodToolCallback objects instead of bare names.
- Ensure the Spring context is fully started so the resolver bean is available before building the agent.
Example fix
// before
ReactAgent.builder().name("a").model(model).tools("getTime").build();
// after
ReactAgent.builder().name("a").model(model).tools("getTime").toolCallbackResolver(resolver).build(); Defensive patterns
Strategy: type-guard
Validate before calling
if (resolver == null && !Collections.disjoint(toolNames, toolNames)) throw new IllegalStateException("Tool names registered but no ToolCallbackResolver set"); Type guard
boolean canResolveByName(ToolCallbackResolver r, List<String> names) { return r != null || names == null || names.isEmpty(); } Try / catch
try { agent = builder.build(); } catch (IllegalStateException e) { if (e.getMessage().startsWith("ToolCallbackResolver is null")) { throw new IllegalStateException("Set .toolCallbackResolver(...) when registering tools by name", e); } throw e; } Prevention
- Whenever passing tool name strings, also set .toolCallbackResolver(...).
- Prefer registering ToolCallback objects over names when no Spring resolver exists.
- Assert resolver presence in a builder factory.
When it happens
Trigger: Building a ReactAgent where tools were supplied as String tool names (e.g. .tools("myTool")) but no ToolCallbackResolver was set on the builder.
Common situations: Using tool-name registration in a plain application without Spring's tool resolution wiring; forgetting .toolCallbackResolver(...) on the builder; constructing DefaultBuilder manually outside Spring context.
Related errors
- No ToolCallback found for tool name:
- Cannot create update map after mergeAll() has been called
- ConfigAgentWatcher is already started
- Default Scheduled Agent Manager is shut down
- LLM may have adapted the tool name
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/a93b7fd38cc18fa4.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/DefaultBuilder.java:258
}
if (CollectionUtils.isNotEmpty(toolCallbackProviders)) {
for (var provider : toolCallbackProviders) {
regularTools.addAll(List.of(provider.getToolCallbacks()));
}
}
if (CollectionUtils.isNotEmpty(toolNames)) {
for (String toolName : toolNames) {
// Skip the tool if it is already present in the request toolCallbacks.
// That might happen if a tool is defined in the options
// both as a ToolCallback and as a tool name.
if (regularTools.stream().anyMatch(tool -> tool.getToolDefinition().name().equals(toolName))) {
continue;
}
if (this.resolver == null) {
throw new IllegalStateException(
"ToolCallbackResolver is null; cannot resolve tool name: " + toolName);
}
ToolCallback toolCallback = this.resolver.resolve(toolName);
if (toolCallback == null) {
logger.warn(POSSIBLE_LLM_TOOL_NAME_CHANGE_WARNING, toolName);
throw new IllegalStateException("No ToolCallback found for tool name: " + toolName);
}
regularTools.add(toolCallback);
}
}
// If regularTools is empty and resolver is provided, try to extract tools from resolver
if (regularTools.isEmpty() && this.resolver != null) {
// Check if resolver also implements ToolCallbackProvider
if (this.resolver instanceof ToolCallbackProvider provider) {
ToolCallback[] resolverTools = provider.getToolCallbacks();
if (resolverTools != null && resolverTools.length > 0) {
regularTools.addAll(List.of(resolverTools));View on GitHub (pinned to f82da0b50f)