vox_types/vox_error.rs
1use facet::Facet;
2use std::fmt;
3
4// r[rpc.fallible.vox-error]
5/// Protocol-level error wrapper distinguishing application errors from vox infrastructure errors.
6///
7/// On the caller side, all return types are wrapped as `Result<T, VoxError<E>>`:
8/// * Infallible `fn foo() -> T` becomes `Result<T, VoxError>`
9/// * Fallible `fn foo() -> Result<T, E>` becomes `Result<T, VoxError<E>>`
10#[derive(Debug, Clone, Facet)]
11#[repr(u8)]
12pub enum VoxError<E = ::core::convert::Infallible> {
13 /// The handler ran and returned an application error.
14 User(E),
15
16 /// No handler recognized the method ID.
17 UnknownMethod,
18
19 /// The arguments could not be deserialized.
20 InvalidPayload(String),
21
22 /// The call was cancelled before completion (e.g. handler dropped without replying).
23 Cancelled,
24
25 /// The underlying connection closed while the call was in flight.
26 ConnectionClosed,
27
28 /// The session shut down while the call was in flight.
29 SessionShutdown,
30
31 /// The call could not be sent because the transport is dead.
32 SendFailed,
33
34 /// The runtime refused to guess after recovery.
35 Indeterminate,
36}
37
38impl<E> VoxError<E> {
39 // r[impl rpc.fallible.vox-error.retryable]
40 // r[impl schema.errors.non-retryable]
41 /// Returns `true` if retrying the same operation on a fresh connection may succeed.
42 ///
43 /// `InvalidPayload`, `UnknownMethod`, `User`, `Cancelled`, and `Indeterminate`
44 /// are permanent failures — retrying them against the same peer will reproduce
45 /// the same outcome.
46 pub fn is_retryable(&self) -> bool {
47 matches!(
48 self,
49 Self::ConnectionClosed | Self::SessionShutdown | Self::SendFailed
50 )
51 }
52}
53
54impl<E: fmt::Display> fmt::Display for VoxError<E> {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Self::User(error) => write!(f, "{error}"),
58 Self::UnknownMethod => f.write_str("unknown vox method call"),
59 Self::InvalidPayload(message) => write!(f, "invalid vox payload: {message}"),
60 Self::Cancelled => f.write_str("vox request cancelled"),
61 Self::ConnectionClosed => f.write_str("vox connection closed"),
62 Self::SessionShutdown => f.write_str("vox session shutdown"),
63 Self::SendFailed => f.write_str("vox send failed"),
64 Self::Indeterminate => f.write_str("indeterminate vox error"),
65 }
66 }
67}
68
69impl<E: fmt::Debug + fmt::Display> std::error::Error for VoxError<E> {}