Errors and cancellation types#
tractor extends trio’s “exceptions always propagate” rule
across the process boundary: a crash in any actor is serialized as
an Error msg, shuttled over IPC, and re-raised in the linked
parent scope as a boxed RemoteActorError — preserving
the original type, traceback text and source-actor identity, even
across multi-hop relays (a.k.a. “inceptions”).
The most-used types below are importable from tractor
directly; the remainder live in tractor._exceptions (not yet
re-exported at top level).
Boxed remote errors#
- exception tractor.RemoteActorError(message, ipc_msg=None, boxed_type=None, **extra_msgdata)[source]#
A box(ing) type which bundles a remote actor BaseException for (near identical, and only if possible,) local object/instance re-construction in the local process memory domain.
Normally each instance is expected to be constructed from a special “error” IPC msg sent by some remote actor-runtime.
- Parameters:
message (str)
ipc_msg (Error | None)
boxed_type (Type[BaseException] | None)
- Return type:
None
- property boxed_type: Type[BaseException] | None#
Error type boxed by last actor IPC hop.
- pformat(with_type_header=True)[source]#
Format any boxed remote error by multi-line display of,
error’s src or relay actor meta-data,
remote runtime env’s traceback,
With optional control over the format of,
whether the boxed traceback is ascii-decorated with a surrounding “box” annotating the embedded stack-trace.
if the error’s type name should be added as margins around the field and tb content like:
<RemoteActorError(.. <<multi-line-content>> .. )>
the placement of the .message: str (explicit equiv of .args[0]), either placed below the .tb_str or in the first line’s header when the error is raised locally (since the type name is already implicitly shown by python).
try:
async with portal.open_context(ep_fn) as (ctx, first):
...
except tractor.RemoteActorError as rae:
if rae.boxed_type is ValueError:
... # remote task raised a `ValueError`
- exception tractor.ContextCancelled(message, ipc_msg=None, boxed_type=None, **extra_msgdata)[source]#
Bases:
RemoteActorErrorInter-actor task context was cancelled by either a call to
Portal.cancel_actor()orContext.cancel().- Parameters:
message (str)
ipc_msg (Error | None)
boxed_type (Type[BaseException] | None)
- Return type:
None
- property canceller: tuple[str, str] | None#
Return the (maybe) Actor.uid for the requesting-author of this ctxc.
Emit a warning msg when .canceller has not been set, which usually idicates that a None msg-loop setinel was sent before expected in the runtime. This can happen in a few situations:
(simulating) an IPC transport network outage
a (malicious) pkt sent specifically to cancel an actor’s runtime non-gracefully without ensuring ongoing RPC tasks are incrementally cancelled as is done with:
`Actor` |_`.cancel()` |_`.cancel_soon()` |_`._cancel_task()`
Note
Inspect ContextCancelled.canceller (the requesting
actor’s uid) to distinguish a self-requested cancel (absorbed
at open_context() exit) from a cross-actor cancel (raised
locally) — the full rules live in Contexts and streaming.
Typed-messaging errors#
- exception tractor.MsgTypeError(message, ipc_msg=None, boxed_type=None, **extra_msgdata)[source]#
Bases:
RemoteActorErrorEquivalent of a runtime TypeError for IPC dialogs.
Raise when any IPC wire-message is decoded to have invalid field values (due to type) or for other MsgCodec related violations such as having no extension-type for a field with a custom type but no enc/dec_hook() support.
Can be raised on the send or recv side of an IPC Channel depending on the particular msg.
Msgs which cause this to be raised on the .send() side (aka in the “ctl” dialog phase) include: - Start - Started - Return
Those which cause it on on the .recv() side (aka the “nasty streaming” dialog phase) are: - Yield - TODO: any embedded .pld type defined by user code?
Normally the source of an error is re-raised from some .msg._codec decode which itself raises in a backend interchange lib (eg. a msgspec.ValidationError).
- Parameters:
message (str)
ipc_msg (Error | None)
boxed_type (Type[BaseException] | None)
- Return type:
None
An “IPC TypeError”: a message failed validation against the
active msg-spec / pld_spec (see Typed messaging: tractor.msg). Raised
sender-side for control msgs (Started/Return) and
receiver-side for stream Yield payloads.
- exception tractor._exceptions.StreamOverrun(message, ipc_msg=None, boxed_type=None, **extra_msgdata)[source]#
Bases:
RemoteActorError,TooSlowError- Parameters:
message (str)
ipc_msg (Error | None)
boxed_type (Type[BaseException] | None)
- Return type:
None
The sender out-paced the receiver’s buffer on a
MsgStream opened without
allow_overruns=True; subtypes trio.TooSlowError.
Transport and runtime errors#
- exception tractor.TransportClosed(message, loglevel='transport', src_exc=None, raise_on_report=False)[source]#
IPC transport (protocol) connection was closed or broke and indicates that the wrapping communication Channel can no longer be used to send/receive msgs from the remote peer.
- exception tractor.ModuleNotExposed[source]#
Bases:
ModuleNotFoundErrorThe requested module is not exposed for RPC
Raised when an RPC requests a function from a module not listed
in the target actor’s enable_modules allowlist —
capability-style access control, not an import bug on your end ;)
- exception tractor._exceptions.NoRuntime[source]#
Bases:
RuntimeErrorThe root actor has not been initialized yet
Raised by tractor.current_actor() (and friends) when no
actor runtime is up in the current process.
- exception tractor._exceptions.ActorTooSlowError[source]#
Bases:
RuntimeFailureA peer-Actor failed to ack an actor-runtime cancel-cascade request (e.g. Portal.cancel_actor() -> Actor.cancel()) within the bounded wait window.
Distinct exc-type (NOT a trio.TooSlowError subclass) so that except trio.TooSlowError: blocks elsewhere in the test-suite or tractor internals do NOT silently mask actor-cancel timeouts — these MUST propagate so a supervisor can escalate to proc.terminate() (hard-kill) per SC-discipline:
graceful cancel-req -> bounded wait -> hard-kill
Reason: see #subint_forkserver duplicate-name hang diagnosis where Portal.cancel_actor() silently swallowed the timeout and the supervisor never escalated, leaving a same-named sibling subactor parked forever.
A peer actor failed to ack a cancel request within the bounded
wait — the SC-sanctioned escalation signal from APIs like
Portal.cancel_actor(raise_on_timeout=True). Catch it to
escalate (e.g. hard-kill via the supervising
ActorNursery); never just ignore it, that’s how
zombies happen.
See also
Contexts and streaming for how cancellation and errors flow
through a Context, Debugging and devx: tractor.devx for
crash-handling REPL tooling (debug_mode, post-mortems),
and Cancellation and error propagation for the full SC-cancellation
story.