1use rivet_error::*;
2use serde::{Deserialize, Serialize};
3use serde_json::Value as JsonValue;
4
5pub fn public_error_status_code(group: &str, code: &str) -> Option<u16> {
6 match (group, code) {
7 ("auth", "forbidden") => Some(403),
8 ("actor", "action_not_found") => Some(404),
9 ("actor", "action_timed_out") => Some(408),
10 ("actor", "aborted") => Some(400),
11 ("message", "incoming_too_long" | "outgoing_too_long") => Some(400),
12 (
13 "queue",
14 "full"
15 | "message_too_large"
16 | "message_invalid"
17 | "invalid_payload"
18 | "invalid_completion_payload"
19 | "already_completed"
20 | "previous_message_not_completed"
21 | "complete_not_configured"
22 | "timed_out",
23 ) => Some(400),
24 ("user", _) => Some(400),
25 _ => None,
26 }
27}
28
29pub(crate) fn is_internal_error(group: &str, code: &str) -> bool {
30 (group == "core" || group == "rivetkit") && code == "internal_error"
31}
32
33pub(crate) fn is_client_error_public(group: &str, code: &str) -> bool {
34 public_error_status_code(group, code).is_some()
35}
36
37pub(crate) fn client_error_message<'a>(group: &str, code: &str, message: &'a str) -> &'a str {
40 if is_client_error_public(group, code) {
41 message
42 } else {
43 INTERNAL_ERROR.default_message
44 }
45}
46
47pub(crate) fn client_error_metadata<'a>(
50 group: &str,
51 code: &str,
52 metadata: Option<&'a JsonValue>,
53) -> Option<&'a JsonValue> {
54 if is_client_error_public(group, code) {
55 metadata
56 } else {
57 None
58 }
59}
60
61#[derive(RivetError, Debug, Clone, Deserialize, Serialize)]
62#[error("actor")]
63pub enum ActorLifecycle {
64 #[error("starting", "Actor is starting.")]
65 Starting,
66
67 #[error("not_ready", "Actor is not ready.")]
68 NotReady,
69
70 #[error("stopping", "Actor is stopping.")]
71 Stopping,
72
73 #[error("destroying", "Actor is destroying.")]
74 Destroying,
75
76 #[error("shutdown_timeout", "Actor shutdown timed out.")]
77 ShutdownTimeout,
78
79 #[error("dropped_reply", "Actor reply channel was dropped without a response.")]
80 DroppedReply,
81
82 #[error(
83 "overloaded",
84 "Actor is overloaded.",
85 "Actor channel '{channel}' is overloaded while attempting to {operation} (capacity {capacity})."
86 )]
87 Overloaded {
88 channel: String,
89 capacity: usize,
90 operation: String,
91 },
92}
93
94#[derive(RivetError, Debug, Clone, Deserialize, Serialize)]
95#[error("actor")]
96pub enum ActorRuntime {
97 #[error(
98 "not_configured",
99 "Actor capability is not configured.",
100 "Actor capability '{component}' is not configured."
101 )]
102 NotConfigured { component: String },
103
104 #[error(
105 "not_found",
106 "Actor resource was not found.",
107 "Actor {resource} '{id}' was not found."
108 )]
109 NotFound { resource: String, id: String },
110
111 #[error(
112 "not_registered",
113 "Actor factory is not registered.",
114 "Actor factory '{actor_name}' is not registered."
115 )]
116 NotRegistered { actor_name: String },
117
118 #[error("missing_input", "Actor input is missing.")]
119 MissingInput,
120
121 #[error(
122 "invalid_operation",
123 "Actor operation is invalid.",
124 "Actor operation '{operation}' is invalid: {reason}"
125 )]
126 InvalidOperation { operation: String, reason: String },
127
128 #[error(
129 "panicked",
130 "Actor task panicked.",
131 "Actor task panicked while running {operation}."
132 )]
133 Panicked { operation: String },
134}
135
136#[derive(RivetError, Debug, Clone, Deserialize, Serialize)]
137#[error("protocol")]
138pub(crate) enum ProtocolError {
139 #[error(
140 "invalid_http_request",
141 "Invalid HTTP request.",
142 "Invalid HTTP request {field}: {reason}"
143 )]
144 InvalidHttpRequest { field: String, reason: String },
145
146 #[error(
147 "invalid_http_response",
148 "Invalid HTTP response.",
149 "Invalid HTTP response {field}: {reason}"
150 )]
151 InvalidHttpResponse { field: String, reason: String },
152
153 #[error(
154 "invalid_actor_connect_request",
155 "Invalid actor-connect request.",
156 "Invalid actor-connect request {field}: {reason}"
157 )]
158 InvalidActorConnectRequest { field: String, reason: String },
159
160 #[error(
161 "invalid_persisted_data",
162 "Invalid persisted actor data.",
163 "Invalid persisted {label}: {reason}"
164 )]
165 InvalidPersistedData { label: String, reason: String },
166
167 #[error(
168 "unsupported_encoding",
169 "Unsupported protocol encoding.",
170 "Unsupported protocol encoding '{encoding}'."
171 )]
172 UnsupportedEncoding { encoding: String },
173}
174
175#[derive(RivetError, Debug, Clone, Deserialize, Serialize)]
176#[error("sqlite")]
177pub(crate) enum SqliteRuntimeError {
178 #[error(
179 "unavailable",
180 "SQLite is unavailable.",
181 "Actor database is not available because rivetkit-core was built without the sqlite feature."
182 )]
183 Unavailable,
184
185 #[error("closed", "SQLite database is closed.")]
186 Closed,
187
188 #[error(
189 "not_configured",
190 "SQLite is not configured.",
191 "SQLite {component} is not configured."
192 )]
193 NotConfigured { component: String },
194
195 #[error(
196 "invalid_bind_parameter",
197 "Invalid SQLite bind parameter.",
198 "Invalid SQLite bind parameter {name}: {reason}"
199 )]
200 InvalidBindParameter { name: String, reason: String },
201
202 #[error(
203 "remote_unavailable",
204 "Remote SQLite is unavailable.",
205 "Remote SQLite is unavailable: {reason}"
206 )]
207 RemoteUnavailable { reason: String },
208
209 #[error(
210 "remote_execution_failed",
211 "Remote SQLite execution failed.",
212 "Remote SQLite execution failed: {message}"
213 )]
214 RemoteExecutionFailed { message: String },
215
216 #[error(
217 "remote_indeterminate_result",
218 "Remote SQLite result is indeterminate.",
219 "Remote SQLite {operation} may have completed, but the envoy disconnected before returning a result."
220 )]
221 RemoteIndeterminateResult { operation: String },
222
223 #[error(
224 "remote_fence_mismatch",
225 "Remote SQLite generation is stale.",
226 "Remote SQLite generation is stale: {reason}"
227 )]
228 RemoteFenceMismatch { reason: String },
229}