xmtp_proto/error.rs
1use std::array::TryFromSliceError;
2
3use thiserror::Error;
4use xmtp_common::{ErrorCode, RetryableError};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum ApiEndpoint {
8 Publish,
9 SubscribeGroupMessages,
10 SubscribeWelcomes,
11 UploadKeyPackage,
12 FetchKeyPackages,
13 SendGroupMessages,
14 SendWelcomeMessages,
15 QueryGroupMessages,
16 QueryWelcomeMessages,
17 PublishIdentityUpdate,
18 GetInboxIds,
19 GetIdentityUpdatesV2,
20 VerifyScwSignature,
21 QueryV4Envelopes,
22 PublishEnvelopes,
23 PublishCommitLog,
24 QueryCommitLog,
25 HealthCheck,
26 GetNodes,
27 Path(String),
28 GetNewestGroupMessage,
29}
30
31impl std::fmt::Display for ApiEndpoint {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
33 use ApiEndpoint::*;
34 match self {
35 Publish => write!(f, "publish"),
36 SubscribeGroupMessages => write!(f, "subscribe_group_messages"),
37 SubscribeWelcomes => write!(f, "subscribe_welcomes"),
38 UploadKeyPackage => write!(f, "upload_key_package"),
39 FetchKeyPackages => write!(f, "fetch_key_packages"),
40 SendGroupMessages => write!(f, "send_group_messages"),
41 SendWelcomeMessages => write!(f, "send_welcome_messages"),
42 QueryGroupMessages => write!(f, "query_group_messages"),
43 QueryWelcomeMessages => write!(f, "query_welcome_messages"),
44 PublishIdentityUpdate => write!(f, "publish_identity_update"),
45 GetInboxIds => write!(f, "get_inbox_ids"),
46 GetIdentityUpdatesV2 => write!(f, "get_identity_updates_v2"),
47 VerifyScwSignature => write!(f, "verify_scw_signature"),
48 QueryV4Envelopes => write!(f, "query_v4_envelopes"),
49 PublishEnvelopes => write!(f, "publish_envelopes"),
50 PublishCommitLog => write!(f, "publish_commit_log"),
51 QueryCommitLog => write!(f, "query_commit_log"),
52 HealthCheck => write!(f, "health_check"),
53 GetNodes => write!(f, "get_nodes"),
54 Path(s) => write!(f, "{}", s),
55 GetNewestGroupMessage => write!(f, "get_newest_group_message"),
56 }
57 }
58}
59
60/// General Error types for use when converting/deserializing From/To Protos
61/// Loosely Modeled after serdes [error](https://docs.rs/serde/latest/serde/de/value/struct.Error.html) type.
62/// This general error type avoid circular hard-dependencies on crates further up the tree
63/// (xmtp_id/xmtp_mls) if they had defined the error themselves.
64#[derive(thiserror::Error, Debug, ErrorCode)]
65pub enum ConversionError {
66 /// Missing field.
67 ///
68 /// Required field missing during proto conversion. Not retryable.
69 #[error("missing field {} of type {} during conversion from protobuf", .item, .r#type)]
70 Missing {
71 /// the item being converted
72 item: &'static str,
73 /// type of the item being converted
74 r#type: &'static str,
75 },
76 /// Unspecified field.
77 ///
78 /// Protobuf field is unspecified. Not retryable.
79 #[error("field {} unspecified", _0)]
80 Unspecified(&'static str),
81 /// Deprecated field.
82 ///
83 /// A deprecated protobuf field was used. Not retryable.
84 #[error("field {} deprecated", _0)]
85 Deprecated(&'static str),
86 /// Invalid length.
87 ///
88 /// Data has wrong length for conversion. Not retryable.
89 #[error("type {} has invalid length. expected {} got {}", .item, .expected, .got)]
90 InvalidLength {
91 /// the item being converted
92 item: &'static str,
93 /// expected length of the item being converted
94 expected: usize,
95 /// the length of the received item
96 got: usize,
97 },
98 /// Invalid value.
99 ///
100 /// Data has unexpected value. Not retryable.
101 #[error("type {} invalid. expected {}, got {}", .item, .expected, .got)]
102 InvalidValue {
103 /// the item being converted
104 item: &'static str,
105 /// description of the item expected, i.e 'a negative integer'
106 expected: &'static str,
107 /// description of the value received i.e 'a positive integer'
108 got: String,
109 },
110 /// Decode error.
111 ///
112 /// Protobuf decoding failed. Not retryable.
113 #[error("decoding proto {0}")]
114 Decode(#[from] prost::DecodeError),
115 /// Encode error.
116 ///
117 /// Protobuf encoding failed. Not retryable.
118 #[error("encoding proto {0}")]
119 Encode(#[from] prost::EncodeError),
120 /// Unknown enum value.
121 ///
122 /// Protobuf enum has unrecognized value. Not retryable.
123 #[error("Unknown enum value {0}")]
124 UnknownEnumValue(#[from] prost::UnknownEnumValue),
125 /// Identifier kind that cannot sign.
126 ///
127 /// The identifier kind is a handle or a value that `IdentifierKind` does
128 /// not list. Such an identifier cannot sign, so it cannot be an inbox's
129 /// initial or recovery identifier. Not retryable.
130 #[error("identifier kind {0} cannot sign")]
131 NonSigningIdentifierKind(i32),
132 /// Ed25519 signature error.
133 ///
134 /// Ed25519 signature bytes invalid. Not retryable.
135 // we keep Ed signature bytes on ProtoBuf definitions
136 #[error(transparent)]
137 EdSignature(#[from] ed25519_dalek::ed25519::Error),
138
139 /// Invalid public key.
140 ///
141 /// Public key validation failed. Not retryable.
142 #[error("{} is invalid: {:?}", .description, .value)]
143 InvalidPublicKey {
144 // What kind of key is invalid
145 description: &'static str,
146 // What is the value
147 value: Option<String>,
148 },
149 /// Invalid version.
150 ///
151 /// Protocol version not supported. Not retryable.
152 #[error("version not supported")]
153 InvalidVersion,
154 /// OpenMLS error.
155 ///
156 /// OpenMLS library error. Not retryable.
157 // TODO: Probably should not be apart of conversion,
158 // conversions using openml sshould be put further up the stack
159 #[error(transparent)]
160 OpenMls(#[from] openmls::prelude::Error),
161 /// Protocol message error.
162 ///
163 /// MLS protocol message error. Not retryable.
164 #[error(transparent)]
165 Protocol(#[from] openmls::framing::errors::ProtocolMessageError),
166 /// Builder error.
167 ///
168 /// Builder field not initialized. Not retryable.
169 #[error(transparent)]
170 Builder(#[from] derive_builder::UninitializedFieldError),
171 /// Slice error.
172 ///
173 /// Byte slice conversion failed. Not retryable.
174 #[error(transparent)]
175 Slice(#[from] TryFromSliceError),
176}
177
178// Conversion errors themselves not really retryable because the bytes are static,
179// the conversions are done in-memory, so a retrying a conversion should not change the outcome.
180// The API call is what should be retried.
181// If retry on a conversion error is desired a new error enum + custom Retrayble implementation
182// should be preferred.
183impl RetryableError for ConversionError {
184 fn is_retryable(&self) -> bool {
185 false
186 }
187}
188
189/// Error resulting from proto conversions/mutations
190#[derive(Debug, Error, ErrorCode)]
191pub enum ProtoError {
192 /// Hex error.
193 ///
194 /// Hex encoding/decoding failed. Not retryable.
195 #[error(transparent)]
196 Hex(#[from] hex::FromHexError),
197 /// Decode error.
198 ///
199 /// Protobuf decoding failed. Not retryable.
200 #[error(transparent)]
201 Decode(#[from] prost::DecodeError),
202 /// Encode error.
203 ///
204 /// Protobuf encoding failed. Not retryable.
205 #[error(transparent)]
206 Encode(#[from] prost::EncodeError),
207 /// OpenMLS error.
208 ///
209 /// OpenMLS library error. Not retryable.
210 #[error("Open MLS {0}")]
211 OpenMls(#[from] openmls::prelude::Error),
212 /// MLS protocol message error.
213 ///
214 /// MLS framing error. Not retryable.
215 #[error(transparent)]
216 MlsProtocolMessage(#[from] openmls::framing::errors::ProtocolMessageError),
217 /// Key package error.
218 ///
219 /// Key package verification failed. Not retryable.
220 #[error(transparent)]
221 KeyPackage(#[from] openmls::prelude::KeyPackageVerifyError),
222 /// Not found.
223 ///
224 /// Proto resource not found. Not retryable.
225 #[error("{0} not found")]
226 NotFound(String),
227}