{"record":{"id":"069807052d2450ac","repo":"alibaba/spring-ai-alibaba","slug":"async-tool-execution-failed","errorCode":null,"errorMessage":"Async tool execution failed","messagePattern":"Async tool execution failed","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tool/AsyncToolCallback.java","lineNumber":108,"sourceCode":"\t * @param context the tool execution context\n\t * @return the result string\n\t * @throws RuntimeException if the async operation fails\n\t * @throws ToolCancelledException if the operation was cancelled\n\t */\n\t@Override\n\tdefault String call(String arguments, ToolContext context) {\n\t\ttry {\n\t\t\treturn callAsync(arguments, context).join();\n\t\t}\n\t\tcatch (CompletionException e) {\n\t\t\tThrowable cause = e.getCause();\n\t\t\tif (cause instanceof RuntimeException re) {\n\t\t\t\tthrow re;\n\t\t\t}\n\t\t\tif (cause instanceof Error err) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tthrow new RuntimeException(\"Async tool execution failed\", cause);\n\t\t}\n\t\tcatch (CancellationException e) {\n\t\t\tthrow new ToolCancelledException(\"Tool execution was cancelled\", e);\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this tool executes asynchronously.\n\t * @return true (always async for this interface)\n\t */\n\tdefault boolean isAsync() {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the timeout duration for this tool execution.\n\t * @return the timeout duration, defaults to 5 minutes\n\t */","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tool/AsyncToolCallback.java#L90-L126","documentation":"AsyncToolCallback.call() awaits an async tool execution and, if the underlying future/completable completed exceptionally with a cause that is neither a RuntimeException nor an Error, it wraps the cause in a RuntimeException with the message \"Async tool execution failed\". This keeps checked/other Throwable causes propagatable in the synchronous caller context.","triggerScenarios":"A tool registered through the async callback interface throws a checked Throwable (e.g. IOException, InterruptedException) or its CompletableFuture completes exceptionally with a non-RuntimeException cause; call() unwraps the ExecutionException and re-wraps it.","commonSituations":"Tool methods declaring checked exceptions, I/O failures inside tools, executor/timeout failures surfaced as non-RuntimeException causes, custom tools that complete futures with Exception rather than RuntimeException.","solutions":["Open the cause via getCause() to find the real failure — this message is only a wrapper.","Throw RuntimeException subclasses from tool methods so they propagate unwrapped.","Handle InterruptedException/IOException explicitly inside the tool and convert them to meaningful runtime exceptions.","Catch this RuntimeException at the agent/tool-call boundary and map to a tool error result."],"exampleFix":"// before\nString result = tool.apply(input); // throws IOException\n// after\nString result;\ntry {\n    result = tool.apply(input);\n} catch (IOException e) {\n    throw new UncheckedIOException(\"tool I/O failed\", e);\n}","handlingStrategy":"try-catch","validationCode":"if (cause instanceof RuntimeException || cause instanceof Error) { /* will rethrow as-is; handle earlier */ }","typeGuard":"if (t.getCause() instanceof RuntimeException re) { throw re; }","tryCatchPattern":"try { result = asyncTool.call(input); } catch (RuntimeException e) { Throwable cause = e.getCause(); log.error(\"async tool failed\", cause != null ? cause : e); }","preventionTips":["Throw unchecked exceptions from tool methods","Convert checked exceptions to UncheckedIOException/IllegalStateException inside tools","Always inspect getCause() when diagnosing","Add tests for failing tools"],"tags":["async","tool-execution","runtime-exception","wrapped-cause"],"backgroundTag":"api-request-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}