tokio_actors/error.rs
1//! Error types surfaced by the Tokio Actors runtime.
2
3use thiserror::Error;
4
5use crate::types::ActorId;
6
7/// Result type for actor operations.
8pub type ActorResult<T> = Result<T, ActorError>;
9
10/// Errors returned from user-defined actor logic.
11#[derive(Debug, Error, Clone)]
12pub enum ActorError {
13 /// A custom error message from the actor.
14 #[error("actor logic error: {0}")]
15 User(String),
16 /// The actor was cancelled.
17 #[error("actor cancelled")]
18 Cancelled,
19 /// The actor panicked during execution.
20 #[error("actor panicked: {0}")]
21 Panic(String),
22 /// A spawn error occurred.
23 #[error(transparent)]
24 Spawn(#[from] SpawnError),
25}
26
27impl ActorError {
28 /// Creates a new user-defined error.
29 pub fn user(message: impl Into<String>) -> Self {
30 Self::User(message.into())
31 }
32}
33
34impl From<TimerError> for ActorError {
35 fn from(value: TimerError) -> Self {
36 ActorError::User(value.to_string())
37 }
38}
39
40/// Failures encountered while sending a message asynchronously.
41#[derive(Debug, Error, Clone)]
42pub enum SendError {
43 /// The actor's mailbox is closed (actor stopped).
44 #[error("mailbox closed")]
45 Closed,
46}
47
48/// Failures encountered while sending without awaiting capacity.
49#[derive(Debug, Error, Clone)]
50pub enum TrySendError {
51 /// The mailbox is full.
52 #[error("mailbox full")]
53 Full,
54 /// The mailbox is closed (actor stopped).
55 #[error("mailbox closed")]
56 Closed,
57}
58
59/// Errors reported when awaiting a response from an actor.
60///
61/// The three variants encode three distinct facts:
62/// - [`Closed`](AskError::Closed): the request was never enqueued - it was
63/// definitely NOT processed. Safe to retry unconditionally.
64/// - [`ResponseDropped`](AskError::ResponseDropped): the actor stopped after
65/// the request was enqueued but before replying - it MAY have been partially
66/// processed. Retry only if the operation is idempotent.
67/// - [`Actor`](AskError::Actor): the handler produced this error - either it
68/// returned `Err` or it panicked ([`ActorError::Panic`]).
69#[derive(Debug, Error, Clone)]
70pub enum AskError {
71 /// The actor's mailbox was closed before the request could be enqueued.
72 #[error("mailbox closed before the request was sent")]
73 Closed,
74 /// The actor dropped the response channel without sending a reply.
75 #[error("actor stopped before replying")]
76 ResponseDropped,
77 /// The actor's handler returned an error or panicked.
78 #[error("actor returned error: {0}")]
79 Actor(ActorError),
80}
81
82/// Failures encountered when spawning a child actor.
83#[derive(Debug, Error, Clone)]
84pub enum SpawnError {
85 /// No Tokio runtime was found in the current context.
86 #[error("tokio runtime handle not in scope")]
87 MissingRuntime,
88 /// A child with the same ID is already registered.
89 #[error("child actor `{0}` already registered")]
90 DuplicateChild(ActorId),
91 /// An actor with the given name is already registered in the system.
92 #[error("actor name `{name}` already taken in system `{system}`")]
93 NameTaken {
94 /// The actor name that was already taken.
95 name: String,
96 /// The system in which the collision occurred.
97 system: String,
98 },
99 /// An actor system with the given name already exists.
100 #[error("actor system `{0}` already exists")]
101 SystemNameTaken(String),
102}
103
104/// Errors emitted by the timer subsystem.
105#[derive(Debug, Error, Clone)]
106pub enum TimerError {
107 /// The specified timer ID was not found (already fired or cancelled).
108 #[error("timer id not found")]
109 NotFound,
110}
111
112/// Errors emitted by the stream subsystem.
113#[derive(Debug, Error, Clone)]
114pub enum StreamError {
115 /// The specified stream ID was not found (already finished or cancelled).
116 #[error("stream id not found")]
117 NotFound,
118}
119
120impl From<StreamError> for ActorError {
121 fn from(value: StreamError) -> Self {
122 ActorError::User(value.to_string())
123 }
124}
125
126/// Errors emitted by the supervision subsystem.
127#[derive(Debug, Error, Clone)]
128pub enum SupervisionError {
129 /// The specified child was not found.
130 #[error("child `{0}` not found")]
131 ChildNotFound(ActorId),
132 /// The restart budget has been exhausted.
133 #[error("restart budget exhausted")]
134 BudgetExhausted,
135 /// The factory closure failed during a restart attempt.
136 #[error("factory failed: {0}")]
137 FactoryFailed(String),
138 /// The actor is not configured as a supervisor.
139 #[error("actor is not configured as a supervisor")]
140 NotASupervisor,
141 /// The operation requires the child to be stopped, but it is running.
142 #[error("child `{0}` is running")]
143 ChildRunning(ActorId),
144 /// The child has a restart in flight or is a member of a pending group
145 /// restart; manual operations must wait for it to settle.
146 #[error("child `{0}` is restarting")]
147 ChildRestarting(ActorId),
148 /// The child did not terminate within the kill grace even after its task
149 /// was aborted - it is stuck in a non-yielding loop (see the crate docs on
150 /// abort limits). The supervisor stops waiting instead of hanging.
151 #[error("child `{0}` is unresponsive to kill")]
152 ChildUnresponsive(ActorId),
153}
154
155impl From<SupervisionError> for ActorError {
156 fn from(value: SupervisionError) -> Self {
157 ActorError::User(value.to_string())
158 }
159}