{"record":{"id":"542adb99119b50b6","repo":"microsoft/semantic-kernel","slug":"the-invocation-was-canceled-before-it-could-comple","errorCode":null,"errorMessage":"The invocation was canceled before it could complete.","messagePattern":"The invocation was canceled before it could complete\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"python/semantic_kernel/agents/orchestration/orchestration_base.py","lineNumber":63,"sourceCode":"\n        If a timeout is specified, the method will wait for the result for the specified time.\n        If the result is not available within the timeout, a TimeoutError will be raised but the\n        invocation will not be aborted.\n\n        Args:\n            timeout (int | None): The timeout (seconds) for getting the result. If None, wait indefinitely.\n\n        Returns:\n            TOut: The result of the invocation.\n        \"\"\"\n        if timeout is not None:\n            await asyncio.wait_for(self.event.wait(), timeout=timeout)\n        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()","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/orchestration/orchestration_base.py#L45-L81","documentation":"OrchestrationResult.get() waits on an asyncio.Event; when the event is set with value still None, it checks the cancellation token. If the invocation was canceled (cancel() set the token), get() raises this RuntimeError instead of returning a partial/empty result. It signals the run was aborted before producing output.","triggerScenarios":"Calling `orchestration_result.cancel()` (or the runtime cancelling) and then awaiting `await result.get()`. Also when get() is awaited after the event was set purely by cancellation.","commonSituations":"A user-initiated cancellation (timeout, Ctrl-C handling) followed by reading the result. A parent task canceling the orchestration's task. Calling cancel() then get() to inspect state.","solutions":["Treat cancellation as expected: catch RuntimeError (or asyncio.CancelledError) around get() when you may cancel.","Avoid calling get() after cancel(); if you cancel, don't expect a value.","Use get(timeout=...) so asyncio.wait_for raises TimeoutError instead, leaving the run running."],"exampleFix":"// before\nresult = await orch.invoke(task, runtime)\nresult.cancel()\nvalue = await result.get()  # raises 'canceled before it could complete'\n\n// after\nresult = await orch.invoke(task, runtime)\nresult.cancel()\ntry:\n    value = await result.get()\nexcept RuntimeError:\n    value = None  # expected after cancel","handlingStrategy":"try-catch","validationCode":"# Only read the result if not canceled\nif not result.cancellation_token.is_cancelled():\n    value = await result.get()","typeGuard":"def result_is_canceled(result) -> bool:\n    return result.cancellation_token.is_cancelled()","tryCatchPattern":"try:\n    value = await result.get()\nexcept RuntimeError as e:\n    if \"canceled\" in str(e):\n        value = None  # expected after cancel\n    else:\n        raise","preventionTips":["Don't call get() after cancel(); cancellation means no value.","Use get(timeout=...) to bound waits without canceling.","Catch RuntimeError around get() wherever cancellation is possible."],"tags":["semantic-kernel","orchestration","cancellation","result","asyncio"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}