Skip to main content

xan_actor/
error.rs

1use thiserror::Error;
2
3/// All errors surfaced by the actor system.
4///
5/// Variants gated on `multi-node` only exist when that feature is enabled.
6/// Most user-facing call sites return `Result<_, ActorError>`; match on the
7/// variant when you need to distinguish (e.g. retry on `ActorNotReady` vs.
8/// give up on `AddressNotFound`).
9#[derive(Error, Debug)]
10pub enum ActorError {
11    /// `oneshot::Receiver::await` failed (sender dropped before sending).
12    /// Typically means the actor task died between accepting the message
13    /// and producing a reply.
14    #[error(transparent)]
15    OneshotRecv(#[from] tokio::sync::oneshot::error::RecvError),
16    /// Channel send failed — the receiver was dropped. Indicates the
17    /// target mailbox/loop has shut down. Same variant for both the
18    /// bounded and unbounded mpsc backends.
19    #[error("Failed to send on channel: {0}")]
20    ChannelSend(String),
21    /// Channel `recv` returned `None` — all senders are gone. Same
22    /// variant for both backends.
23    #[error("Failed to recv from channel")]
24    ChannelRecv,
25    /// A timed `send_and_recv` (via
26    /// [`ActorSystem::send_and_recv_with_timeout`] or
27    /// [`ActorSystem::send_and_recv_without_tx_cache_with_timeout`]) did
28    /// not receive its reply within the configured duration. Common
29    /// cause in multi-node mode: the remote peer died or the broker
30    /// dropped the in-flight request.
31    ///
32    /// [`ActorSystem::send_and_recv_with_timeout`]: crate::ActorSystem::send_and_recv_with_timeout
33    /// [`ActorSystem::send_and_recv_without_tx_cache_with_timeout`]: crate::ActorSystem::send_and_recv_without_tx_cache_with_timeout
34    #[error("Operation timed out after {0:?}")]
35    Timeout(std::time::Duration),
36    /// `address_regex` failed to compile (broadcast / restart / unregister).
37    #[error(transparent)]
38    AddressRegexError(#[from] regex::Error),
39
40    /// Tried to register an actor at an address that's already taken on
41    /// this node (and not a restart). Re-registration with the same
42    /// address fails until the existing entry is unregistered.
43    #[error("Address {0} already exists")]
44    AddressAlreadyExist(String),
45    /// `send` / `send_and_recv` / `run_job` could not find the address in
46    /// the local actor map. With `multi-node` this is the local-side
47    /// failure mode after the routing check decides the call is local.
48    #[error("Address {0} not found")]
49    AddressNotFound(String),
50    /// The address exists but the actor's lifecycle is not yet `Receiving`
51    /// after the retry budget (10 × 100 ms). Usually means the actor is
52    /// still in `Starting` / `Restarting`.
53    #[error("Actor that's address is {0} not ready")]
54    ActorNotReady(String),
55    /// Reserved for cases where cloning an actor state fails. Currently
56    /// not produced by the runtime.
57    #[error("Actor clone failed: {0}")]
58    CloneFailed(String),
59    /// `Actor::register` could not reach `actor_system_loop` after 10
60    /// retries — the system is wedged or shutting down.
61    #[error("Unhealthy ActorSystem")]
62    UnhealthyActorSystem,
63    /// Downcast from `Arc<dyn Any>` / `Box<dyn Any>` to the expected
64    /// concrete message or result type failed. Usually means a `send::<T>`
65    /// (or `send_and_recv::<T>`) was routed to an address whose actor type
66    /// doesn't match `T`.
67    #[error("Message type mismatch")]
68    MessageTypeMismatch,
69
70    /// Underlying xanq client IO failed (e.g. broker disconnected, TCP
71    /// reset, broker connect timed out).
72    #[cfg(feature = "multi-node")]
73    #[error("Inter-node IO error: {0}")]
74    InterNodeIo(String),
75    /// `xancode::Codec::decode` failed when turning bytes back into
76    /// `<T as Actor>::Message` (receiver side) or `<T as Actor>::Result`
77    /// (caller side).
78    #[cfg(feature = "multi-node")]
79    #[error("Inter-node decode error: {0}")]
80    InterNodeDecode(String),
81    /// The receiving node got an envelope for an actor type with no
82    /// matching `register_for_inter_node!` entry in its inventory
83    /// registry. Fix by adding the macro call at module scope on both
84    /// nodes.
85    #[cfg(feature = "multi-node")]
86    #[error("Inter-node decoder not registered for actor type {0}")]
87    InterNodeDecoderMissing(String),
88    /// The peer node responded with `ResponseOutcome::Err`, or the
89    /// pending-response channel was dropped (peer crashed mid-call). The
90    /// payload is the original error string from the peer.
91    #[cfg(feature = "multi-node")]
92    #[error("Inter-node remote error: {0}")]
93    InterNodeRemote(String),
94    /// Attempted a cross-node send on an `ActorSystem` created with
95    /// `broker_addr = None`. Provide a broker address (or keep all
96    /// addresses on the local node).
97    #[cfg(feature = "multi-node")]
98    #[error("Inter-node not configured")]
99    InterNodeNotConfigured,
100    /// `Actor::register` was called with `address.node` not equal to the
101    /// system's own `node_name`. Each node can only host actors whose
102    /// addresses claim that node.
103    #[cfg(feature = "multi-node")]
104    #[error("Address {0} is not owned by this node")]
105    AddressNotOwned(String),
106}