{"record":{"id":"582c1738d4dce760","repo":"alibaba/spring-ai-alibaba","slug":"tool-execution-was-cancelled-582c17","errorCode":null,"errorMessage":"Tool execution was cancelled","messagePattern":"Tool execution was cancelled","errorType":"exception","errorClass":"ToolCancelledException","httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tool/CancellationToken.java","lineNumber":58,"sourceCode":" * @since 1.0.0\n * @see DefaultCancellationToken\n * @see CancellableAsyncToolCallback\n */\npublic interface CancellationToken {\n\n\t/**\n\t * Checks if cancellation has been requested.\n\t * @return true if cancelled\n\t */\n\tboolean isCancelled();\n\n\t/**\n\t * Throws ToolCancelledException if cancelled.\n\t * @throws ToolCancelledException if cancellation was requested\n\t */\n\tdefault void throwIfCancelled() throws ToolCancelledException {\n\t\tif (isCancelled()) {\n\t\t\tthrow new ToolCancelledException(\"Tool execution was cancelled\");\n\t\t}\n\t}\n\n\t/**\n\t * Registers a callback to be invoked when cancellation is requested.\n\t *\n\t * <p>If cancellation has already been requested, the callback may be invoked\n\t * immediately (implementation-dependent).</p>\n\t *\n\t * @param callback the callback to run on cancellation\n\t */\n\tvoid onCancel(Runnable callback);\n\n\t/**\n\t * A no-op cancellation token that is never cancelled.\n\t *\n\t * <p>This instance is used as a default when cancellation support is not needed.\n\t * Since this token can never be cancelled, {@link #onCancel(Runnable)} is a no-op","sourceCodeStart":40,"sourceCodeEnd":76,"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/CancellationToken.java#L40-L76","documentation":"CancellationToken.throwIfCancelled() checks isCancelled() and throws ToolCancelledException with message \"Tool execution was cancelled\" when a cancellation has been requested. It is the cooperative-cancellation hook tools call at safe points to abort execution early.","triggerScenarios":"A tool calls token.throwIfCancelled() after CancellationToken.cancel() was invoked from another thread (timeout, user abort, upstream interruption).","commonSituations":"Long-running tools that poll the token between steps; agents cancelling in-flight tool calls when the user interrupts; watchdog timeouts cancelling tools.","solutions":["Catch ToolCancelledException in the tool and return/partial result gracefully instead of letting it bubble as an error.","Verify no code path cancels the token prematurely (e.g. scope closing too early).","Call throwIfCancelled() at regular checkpoints in long-running tools for fast aborts.","Clean up resources in a finally block so cancellation leaves no leaked state."],"exampleFix":"// before\nfor (Item i : items) { process(i); }\n// after\nfor (Item i : items) {\n    token.throwIfCancelled();\n    process(i);\n}","handlingStrategy":"try-catch","validationCode":"if (token.isCancelled()) { /* skip work before starting */ }","typeGuard":null,"tryCatchPattern":"try { token.throwIfCancelled(); doWork(); } catch (ToolCancelledException e) { cleanup(); return partialResult; }","preventionTips":["Insert throwIfCancelled checkpoints in loops","Use finally blocks for resource cleanup","Do not cache 'not cancelled' decisions across long steps","Only cancel tokens deliberately"],"tags":["cancellation","tool-execution","cooperative-cancellation"],"backgroundTag":"request-timeout","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"}