{"record":{"id":"77fc1b06c6eed097","repo":"google-gemini/gemini-cli","slug":"execution-aborted","errorCode":null,"errorMessage":"Execution aborted","messagePattern":"Execution aborted","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/a2a-server/src/agent/executor.ts","lineNumber":747,"sourceCode":"            `[CoderAgentExecutor] Starting main execution for message ${userMessage.messageId} for task ${taskId}.`,\n          );\n          this.executingTasks.add(taskId);\n\n          let agentTurnActive = true;\n          logger.info(\n            `[CoderAgentExecutor] Task ${taskId}: Processing user turn.`,\n          );\n          let agentEvents = currentTask.acceptUserMessage(\n            requestContext,\n            abortSignal,\n          );\n\n          while (agentTurnActive) {\n            if (abortSignal.aborted) {\n              logger.info(\n                `[CoderAgentExecutor] Task ${taskId} aborted before turn. Exiting loop.`,\n              );\n              throw new Error('Execution aborted');\n            }\n            logger.info(\n              `[CoderAgentExecutor] Task ${taskId}: Processing agent turn (LLM stream).`,\n            );\n            const toolCallRequests: ToolCallRequestInfo[] = [];\n            for await (const event of agentEvents) {\n              if (abortSignal.aborted) {\n                logger.warn(\n                  `[CoderAgentExecutor] Task ${taskId}: Abort signal received during agent event processing.`,\n                );\n                throw new Error('Execution aborted');\n              }\n              if (event.type === GeminiEventType.ToolCallRequest) {\n                toolCallRequests.push(event.value);\n                continue;\n              }\n              await currentTask.acceptAgentMessage(event);\n            }","sourceCodeStart":729,"sourceCodeEnd":765,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/a2a-server/src/agent/executor.ts#L729-L765","documentation":"Thrown at the top of the agent turn loop in CoderAgentExecutor.execute when abortSignal.aborted is already true before processing a turn. It is the executor's cooperative-cancellation exit: an AbortController (tracked in activeAbortControllers) was triggered, typically by an explicit cancel request or a secondary execution loop being superseded. The error is intended to unwind the turn, not signal a defect.","triggerScenarios":"Client sends a tasks/cancel (or the SDK cancels) for an in-flight task while the executor is between turns; the abort controller for the task is aborted, and on the next iteration of `while (agentTurnActive)` the check at line 743 fires. Also occurs when a primary-execution race aborts a secondary loop.","commonSituations":"User hits stop/cancel in a UI mid-run; a duplicate message for the same task triggers the explicit-cancel path for the prior in-flight run; abort signal wired from request timeout.","solutions":["Treat this error as expected control flow: catch it at the caller and transition the task to a 'canceled'/'failed' state rather than logging a stack trace.","Verify the cancel surface (tasks/cancel handler) is only invoked deliberately, not by a retry/debounce bug that double-fires.","If aborts happen spuriously, check whether the secondary-execution guard at executor.ts:700 is incorrectly throwing for non-aborted errors.","Confirm the AbortController is registered in activeAbortControllers so cancellation reaches the right signal."],"exampleFix":"// before\ntry {\n  await agentExecutor.execute(requestContext, eventBus);\n} catch (e) {\n  logger.error('Execution failed', e);\n}\n\n// after\ntry {\n  await agentExecutor.execute(requestContext, eventBus);\n} else if (e instanceof Error && e.message === 'Execution aborted') {\n  logger.info(`Task ${taskId} was aborted by cancel signal.`);\n  publishTaskState(eventBus, taskId, 'canceled');\n} else {\n  logger.error('Execution failed', e);\n}","handlingStrategy":"try-catch","validationCode":"// Check before entering the loop / before delegating to execute:\nif (abortSignal?.aborted) {\n  publishTaskState(eventBus, taskId, 'canceled');\n  return;\n}\nawait agentExecutor.execute(requestContext, eventBus);","typeGuard":null,"tryCatchPattern":"try {\n  await agentExecutor.execute(requestContext, eventBus);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Execution aborted' && abortSignal?.aborted) {\n    logger.info(`Task ${taskId} canceled by client.`);\n    publishTaskState(eventBus, taskId, 'canceled');\n    return;\n  }\n  throw e;\n}","preventionTips":["Treat 'Execution aborted' as a sentinel message, not a defect - match the string in your handler.","Register the AbortController in activeAbortControllers so cancel reaches the right execution.","Do not share one AbortController across multiple concurrent tasks.","Forward abortSignal into acceptUserMessage/scheduleToolCalls so mid-stream cancel actually stops I/O."],"tags":["abort","cancellation","execution-loop","control-flow"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}