microsoft/semantic-kernel · warning · RuntimeError
The invocation was canceled before it could complete.
Error message
The invocation was canceled before it could complete.
What it means
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.
Source
Thrown at python/semantic_kernel/agents/orchestration/orchestration_base.py:63
If a timeout is specified, the method will wait for the result for the specified time.
If the result is not available within the timeout, a TimeoutError will be raised but the
invocation will not be aborted.
Args:
timeout (int | None): The timeout (seconds) for getting the result. If None, wait indefinitely.
Returns:
TOut: The result of the invocation.
"""
if timeout is not None:
await asyncio.wait_for(self.event.wait(), timeout=timeout)
else:
await self.event.wait()
if self.value is None:
if self.cancellation_token.is_cancelled():
raise RuntimeError("The invocation was canceled before it could complete.")
if self.exception is not None:
raise self.exception
raise RuntimeError("The invocation did not produce a result.")
return self.value
def cancel(self) -> None:
"""Cancel the invocation.
This method will cancel the invocation.
Actors that have received messages will continue to process them, but no new messages will be processed.
"""
if self.cancellation_token.is_cancelled():
raise RuntimeError("The invocation has already been canceled.")
if self.event.is_set():
raise RuntimeError("The invocation has already been completed.")
self.cancellation_token.cancel()
self.event.set()View on GitHub (pinned to c028a0c7dc)
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.
Example fix
// before
result = await orch.invoke(task, runtime)
result.cancel()
value = await result.get() # raises 'canceled before it could complete'
// after
result = await orch.invoke(task, runtime)
result.cancel()
try:
value = await result.get()
except RuntimeError:
value = None # expected after cancel Defensive patterns
Strategy: try-catch
Validate before calling
# Only read the result if not canceled
if not result.cancellation_token.is_cancelled():
value = await result.get() Type guard
def result_is_canceled(result) -> bool:
return result.cancellation_token.is_cancelled() Try / catch
try:
value = await result.get()
except RuntimeError as e:
if "canceled" in str(e):
value = None # expected after cancel
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- The invocation has already been canceled.
- The invocation has already been completed.
- The invocation did not produce a result.
- A complete listen_for condition is required for orchestratio
- At least one then action is required for orchestration steps
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/542adb99119b50b6.
Report an issue: GitHub.