alibaba/spring-ai-alibaba · error · IllegalStateException
No ToolCallback found for tool name:
Error message
No ToolCallback found for tool name:
What it means
In gatherLocalTools, when a registered tool name cannot be resolved by the ToolCallbackResolver (resolver.resolve returns null) the builder logs a warning that the LLM may have changed the tool name and throws IllegalStateException. It means a referenced tool name matches no known ToolCallback.
Solutions
- Fix the tool name string to exactly match the registered tool's name.
- Verify the tool is registered: annotate the method with @Tool and ensure it's picked up by ToolCallbacks/method scanning.
- Print resolver.resolve(name) for each configured name at startup to fail fast with a clear list of available tools.
- If names come from an LLM/model output, sanitize or map them before registering.
Example fix
// before
.tools("get_weathr")
// after
.tools("getWeather") Defensive patterns
Strategy: validation
Validate before calling
for (String name : toolNames) {
if (resolver.resolve(name) == null)
throw new IllegalStateException("Unknown tool name before build(): " + name);
} Try / catch
try { agent = builder.build(); } catch (IllegalStateException e) { if (e.getMessage().startsWith("No ToolCallback found")) { log.error("Registered tools: {}", availableToolNames(resolver)); } throw e; } Prevention
- Keep tool names in constants shared between @Tool definitions and agent configs.
- Add a startup check that resolves every configured tool name and lists valid alternatives on failure.
- Re-check names after refactoring @Tool methods.
When it happens
Trigger: Passing a tool name string that no resolver bean provides, a typo in the tool name, or the tool bean not being registered/scanned when build() runs.
Common situations: Renaming an @Tool method without updating the agent's tool name list; tools defined in a module not on the classpath; resolution happening before the tool beans are registered.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- ToolCallbackResolver is null; cannot resolve 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/511dfb5291c9822a.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/DefaultBuilder.java:264
}
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));
if (logger.isDebugEnabled()) {
logger.debug("Extracted {} tools from ToolCallbackResolver (ToolCallbackProvider)",
resolverTools.length);
}
}
} else {View on GitHub (pinned to f82da0b50f)