alibaba/spring-ai-alibaba · warning

Failed to extract ShellTool2 from tool: {}

Error message

Failed to extract ShellTool2 from tool: {}

What it means

ShellToolAgentHook.injectTool() logs this warning when a registered ToolCallback cannot be unwrapped into a ShellTool2 instance. The hook accepts FunctionToolCallbacks whose delegate (or nested delegate chain) is a ShellTool2; if extraction fails, shellTool2 stays null and later hook phases log the 'No ShellTool2 injected' warnings and are skipped.

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/hook/shelltool/ShellToolAgentHook.java:143

	public void injectTool(ToolCallback toolCallback) {
		if (shellTool2 != null) {
			// Tool already injected
			return;
		}

		log.info("ShellToolAgentHook: Processing tool callback for shell tool extraction");

		try {
			// Extract ShellTool2
			ShellTool2 extractedShellTool2 = extractShellTool2(toolCallback);
			if (extractedShellTool2 != null) {
				this.shellTool2 = extractedShellTool2;
				log.info("Successfully extracted and injected ShellTool2 from tool: {}",
						toolCallback.getToolDefinition().name());
				return;
			}

			log.warn("Failed to extract ShellTool2 from tool: {}",
					toolCallback.getToolDefinition().name());
		} catch (Exception e) {
			log.error("Error extracting ShellTool2 from tool callback", e);
		}
	}

	/**
	 * Extract ShellTool2 instance from ToolCallback using reflection.
	 * Supports MethodToolCallback wrapping ShellTool2 (with @Tool annotation).
	 */
	private ShellTool2 extractShellTool2(ToolCallback toolCallback) {
		try {
			Class<?> clazz = toolCallback.getClass();

			// Look for 'toolObject' field in MethodToolCallback
			while (clazz != null) {
				try {
					Field toolObjectField = clazz.getDeclaredField("toolObject");

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Register the actual ShellTool2 (or ShellTool2.builder()...buildToolCallback()) so extraction succeeds
  2. If using a wrapper, expose the underlying ShellTool2 where the hook expects it, or inject ShellTool2 directly into the hook builder
  3. Log/inspect the callback's delegate chain and compare against the supported types in ShellToolAgentHook.injectTool
  4. Check for dependency version mismatch between spring-ai-alibaba-agent-framework modules

Example fix

// before
agentBuilder.tools(myCustomShellWrapperCallback); // hook cannot extract ShellTool2
// after
agentBuilder.tools(shellTool2)
    .hooks(ShellToolAgentHook.builder().shellTool2(shellTool2).build());
Defensive patterns

Strategy: type-guard

Validate before calling

Objects.requireNonNull(toolCallback, "toolCallback must not be null");
if (!(toolCallback instanceof FunctionToolCallback)) { log.warn("injectTool expects FunctionToolCallback wrapping ShellTool2"); }

Type guard

static ShellTool2 extractIfShellTool(ToolCallback cb) {
    if (cb instanceof FunctionToolCallback fcb && fcb.getToolDefinition() != null) {
        Object delegate = fcb.getToolDefinition();
        if (delegate instanceof ShellTool2 st2) return st2;
    }
    return null;
}

Try / catch

try { injectTool(cb); } catch (Exception e) { log.error("ShellTool2 injection failed for {}", cb, e); }

Prevention

When it happens

Trigger: Calling injectTool(toolCallback) (typically from the agent builder wiring tools) with a callback that is not a FunctionToolCallback wrapping ShellTool2, or whose delegate is of an unexpected type, so the cast/extraction throws or returns nothing.

Common situations: Registering a custom or third-party shell tool callback instead of the framework ShellTool2; wrapping ShellTool2 in your own decorator so reflective extraction fails; version drift where the delegate class moved packages; calling injectTool with a null callback.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/8f8b726a6a319421. Report an issue: GitHub.