{"record":{"id":"8ea0c91fa67e49f9","repo":"microsoft/semantic-kernel","slug":"the-invocation-has-already-been-canceled","errorCode":null,"errorMessage":"The invocation has already been canceled.","messagePattern":"The invocation has already been canceled\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"python/semantic_kernel/agents/orchestration/orchestration_base.py","lineNumber":76,"sourceCode":"        else:\n            await self.event.wait()\n\n        if self.value is None:\n            if self.cancellation_token.is_cancelled():\n                raise RuntimeError(\"The invocation was canceled before it could complete.\")\n            if self.exception is not None:\n                raise self.exception\n            raise RuntimeError(\"The invocation did not produce a result.\")\n        return self.value\n\n    def cancel(self) -> None:\n        \"\"\"Cancel the invocation.\n\n        This method will cancel the invocation.\n        Actors that have received messages will continue to process them, but no new messages will be processed.\n        \"\"\"\n        if self.cancellation_token.is_cancelled():\n            raise RuntimeError(\"The invocation has already been canceled.\")\n        if self.event.is_set():\n            raise RuntimeError(\"The invocation has already been completed.\")\n\n        self.cancellation_token.cancel()\n        self.event.set()\n\n\n@experimental\nclass OrchestrationBase(ABC, Generic[TIn, TOut]):\n    \"\"\"Base class for multi-agent orchestration.\"\"\"\n\n    t_in: type[TIn] | None = None\n    t_out: type[TOut] | None = None\n\n    def __init__(\n        self,\n        members: list[Agent],\n        name: str | None = None,","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/orchestration/orchestration_base.py#L58-L94","documentation":"OrchestrationResult.cancel() first checks whether the cancellation token is already canceled and refuses a double-cancel. Cancellation is idempotent by design; calling cancel() twice is a usage error.","triggerScenarios":"Calling `result.cancel()` more than once on the same OrchestrationResult instance.","commonSituations":"A cleanup/finally block that cancels, combined with another cancel on timeout or error. Multiple components (e.g. a timeout handler and a shutdown handler) both canceling the same result.","solutions":["Guard cancel() with `if not result.cancellation_token.is_cancelled(): result.cancel()`.","Centralize cancellation in one place (e.g. a single finally block) rather than canceling from multiple handlers.","Track cancellation state yourself and skip redundant calls."],"exampleFix":"// before\nresult.cancel()\nresult.cancel()  # raises 'already been canceled'\n\n// after\nresult.cancel()\nif not result.cancellation_token.is_cancelled():\n    result.cancel()","handlingStrategy":"validation","validationCode":"# Idempotent cancel\nif not result.cancellation_token.is_cancelled():\n    result.cancel()","typeGuard":"def result_already_canceled(result) -> bool:\n    return result.cancellation_token.is_cancelled()","tryCatchPattern":null,"preventionTips":["Cancel from a single place (e.g. one finally block).","Guard cancel() with the is_cancelled() check.","Avoid wiring multiple handlers to cancel the same result."],"tags":["semantic-kernel","orchestration","cancellation","result","double-cancel"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}