Skip to main content

softchat/
error.rs

1use thiserror::Error;
2
3/// Stable, redacted failures exposed by Softchat.
4#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
5#[cfg_attr(feature = "native-bindings", derive(uniffi::Error))]
6pub enum SoftchatError {
7    /// The supplied secret key is not one valid 32-byte secp256k1 scalar.
8    #[error("invalid secret key")]
9    InvalidSecretKey,
10
11    /// The supplied public key is not one valid 32-byte x-only public key.
12    #[error("invalid public key")]
13    InvalidPublicKey,
14
15    /// The supplied event ID is malformed or does not match the event body.
16    #[error("invalid Nostr event ID")]
17    InvalidEventId,
18
19    /// The supplied Schnorr signature is malformed or does not verify.
20    #[error("invalid Nostr event signature")]
21    InvalidEventSignature,
22
23    /// The event kind is outside the NIP-01 16-bit range.
24    #[error("invalid Nostr event kind")]
25    InvalidEventKind,
26
27    /// The event timestamp cannot be represented exactly on every target.
28    #[error("invalid Nostr event timestamp")]
29    InvalidEventTimestamp,
30
31    /// A NIP-01 tag is not an array containing at least one string.
32    #[error("invalid Nostr event tag")]
33    InvalidEventTag,
34
35    /// The event is not valid NIP-01 JSON.
36    #[error("invalid Nostr event JSON")]
37    InvalidEventJson,
38
39    /// The encoded event exceeds the portable Softchat input bound.
40    #[error("Nostr event is too large")]
41    EventTooLarge,
42
43    /// Signing failed after the event draft and identity were validated.
44    #[error("Nostr event signing failed")]
45    EventSigningFailed,
46
47    /// A NIP-59 envelope could not be created from the supplied inputs.
48    #[error("NIP-59 envelope creation failed")]
49    Nip59EnvelopeCreationFailed,
50
51    /// A NIP-59 envelope failed route, structure, or authentication checks.
52    #[error("invalid NIP-59 envelope")]
53    InvalidNip59Envelope,
54
55    /// A one-to-one NIP-17 text rumor could not be created.
56    #[error("NIP-17 text message creation failed")]
57    Nip17MessageCreationFailed,
58
59    /// A rumor is not a valid one-to-one NIP-17 text message.
60    #[error("invalid NIP-17 text message")]
61    InvalidNip17Message,
62
63    /// A NIP-19 display identifier is malformed, unsupported, or oversized.
64    #[error("invalid NIP-19 identifier")]
65    InvalidNip19Identifier,
66
67    /// A relay frame is malformed, unsupported, oversized, or has invalid arity.
68    #[error("invalid relay frame")]
69    InvalidRelayFrame,
70
71    /// A NIP-01 relay filter is malformed or exceeds the portable bounds.
72    #[error("invalid relay filter")]
73    InvalidRelayFilter,
74
75    /// A NIP-42 authentication request is malformed or does not match its context.
76    #[error("invalid relay authentication")]
77    InvalidRelayAuthentication,
78
79    /// An EVENTS batch or its acknowledgement set violates the Softchat profile.
80    #[error("invalid relay batch")]
81    InvalidRelayBatch,
82
83    /// Inline Softchat attachment metadata is malformed or outside its bounds.
84    #[error("invalid attachment metadata")]
85    InvalidAttachmentMetadata,
86
87    /// Attachment bytes exceed the bounded in-memory compatibility operation.
88    #[error("attachment is too large")]
89    AttachmentTooLarge,
90
91    /// Attachment encryption failed after validation.
92    #[error("attachment encryption failed")]
93    AttachmentEncryptionFailed,
94
95    /// Attachment authentication or decryption failed.
96    #[error("attachment decryption failed")]
97    AttachmentDecryptionFailed,
98
99    /// A NIP-98 request plan has an invalid method, URL, payload, or redirect.
100    #[error("invalid HTTP authorization request")]
101    InvalidHttpAuthorization,
102
103    /// A typed Softchat chat event is malformed or violates its profile.
104    #[error("invalid Softchat event")]
105    InvalidSoftchatEvent,
106
107    /// A canonical Softchat event could not be created from the supplied values.
108    #[error("Softchat event creation failed")]
109    SoftchatEventCreationFailed,
110
111    /// A pure event-history projection contains unauthorized or malformed input.
112    #[error("invalid Softchat event projection")]
113    InvalidSoftchatProjection,
114
115    /// A private metadata rumor or its retained JSON is invalid.
116    #[error("invalid private user metadata")]
117    InvalidUserMetadata,
118
119    /// A private NIP-02 contact backup is malformed or ambiguous.
120    #[error("invalid private contact list")]
121    InvalidContactList,
122
123    /// NIP-78 or Softchat app-data content is malformed or unauthorized.
124    #[error("invalid application data")]
125    InvalidApplicationData,
126
127    /// A relay-session transition is invalid for its current state.
128    #[error("invalid relay session transition")]
129    InvalidRelaySession,
130
131    /// A bounded relay-session queue cannot accept more work.
132    #[error("relay session queue is full")]
133    RelaySessionQueueFull,
134
135    /// A delivery transition or retry result is contradictory.
136    #[error("invalid delivery state")]
137    InvalidDeliveryState,
138
139    /// A platform persistence result does not match its requested transaction.
140    #[error("invalid persistence result")]
141    InvalidPersistenceResult,
142
143    /// An account-scoped operation, event-copy, or delivery plan is malformed.
144    #[error("invalid account operation")]
145    InvalidAccountOperation,
146
147    /// A command identifier was reused with a different canonical payload.
148    #[error("command identifier conflicts with an existing operation")]
149    CommandConflict,
150
151    /// The same canonical account database is already open in this process.
152    #[error("account database is already open")]
153    AccountAlreadyOpen,
154
155    /// The account was closed and cannot accept additional work.
156    #[error("account is closed")]
157    AccountClosed,
158
159    /// A versioned account-settings value or patch is malformed.
160    #[error("invalid account settings")]
161    InvalidAccountSettings,
162
163    /// A logical media operation or transition is malformed.
164    #[error("invalid media operation")]
165    InvalidMediaOperation,
166
167    /// A correlated system action is unknown to this SDK version.
168    #[error("unsupported system action")]
169    UnsupportedSystemAction,
170
171    /// A relay catalog record or reconciliation transition is malformed.
172    #[error("invalid relay catalog")]
173    InvalidRelayCatalog,
174
175    /// A synchronization phase, page, subscription, or checkpoint is invalid.
176    #[error("invalid synchronization state")]
177    InvalidSyncState,
178
179    /// A Noise NK handshake key or message is malformed or unauthenticated.
180    #[error("invalid Noise handshake")]
181    InvalidNoiseHandshake,
182
183    /// A single-use Noise handshake capability was already consumed.
184    #[error("Noise handshake is already consumed")]
185    NoiseHandshakeConsumed,
186
187    /// An established Noise session was explicitly closed.
188    #[error("Noise session is closed")]
189    NoiseSessionClosed,
190
191    /// Noise transport rejected a frame without exposing cryptographic detail.
192    #[error("Noise transport operation failed")]
193    NoiseTransportFailed,
194
195    /// A Negentropy set, frame, limit, or state transition is invalid.
196    #[error("invalid Negentropy reconciliation")]
197    InvalidNegentropy,
198
199    /// NIP-44 does not permit an empty plaintext.
200    #[error("plaintext must not be empty")]
201    EmptyPlaintext,
202
203    /// The UTF-8 plaintext exceeds the NIP-44 v2 limit.
204    #[error("plaintext is too large")]
205    PlaintextTooLarge,
206
207    /// A language-owned encrypted-message value had the wrong public shape.
208    #[error("invalid encrypted message")]
209    InvalidEncryptedMessage,
210
211    /// The encoded ciphertext exceeds Softchat's cheap pre-decode bound.
212    #[error("ciphertext is too large")]
213    CiphertextTooLarge,
214
215    /// Encryption failed after the inputs were validated.
216    #[error("message encryption failed")]
217    EncryptionFailed,
218
219    /// Authentication, decoding, padding, version, or UTF-8 validation failed.
220    #[error("message decryption failed")]
221    DecryptionFailed,
222
223    /// The local identity's secret material was explicitly erased.
224    #[error("identity is erased")]
225    IdentityErased,
226
227    /// An unexpected implementation failure was redacted at the public boundary.
228    #[error("Softchat operation failed")]
229    InternalFailure,
230}
231
232impl SoftchatError {
233    /// Stable machine-readable error code used by authored language facades.
234    #[must_use]
235    pub const fn code(&self) -> &'static str {
236        match self {
237            Self::InvalidSecretKey => "invalid_secret_key",
238            Self::InvalidPublicKey => "invalid_public_key",
239            Self::InvalidEventId => "invalid_event_id",
240            Self::InvalidEventSignature => "invalid_event_signature",
241            Self::InvalidEventKind => "invalid_event_kind",
242            Self::InvalidEventTimestamp => "invalid_event_timestamp",
243            Self::InvalidEventTag => "invalid_event_tag",
244            Self::InvalidEventJson => "invalid_event_json",
245            Self::EventTooLarge => "event_too_large",
246            Self::EventSigningFailed => "event_signing_failed",
247            Self::Nip59EnvelopeCreationFailed => "nip59_envelope_creation_failed",
248            Self::InvalidNip59Envelope => "invalid_nip59_envelope",
249            Self::Nip17MessageCreationFailed => "nip17_message_creation_failed",
250            Self::InvalidNip17Message => "invalid_nip17_message",
251            Self::InvalidNip19Identifier => "invalid_nip19_identifier",
252            Self::InvalidRelayFrame => "invalid_relay_frame",
253            Self::InvalidRelayFilter => "invalid_relay_filter",
254            Self::InvalidRelayAuthentication => "invalid_relay_authentication",
255            Self::InvalidRelayBatch => "invalid_relay_batch",
256            Self::InvalidAttachmentMetadata => "invalid_attachment_metadata",
257            Self::AttachmentTooLarge => "attachment_too_large",
258            Self::AttachmentEncryptionFailed => "attachment_encryption_failed",
259            Self::AttachmentDecryptionFailed => "attachment_decryption_failed",
260            Self::InvalidHttpAuthorization => "invalid_http_authorization",
261            Self::InvalidSoftchatEvent => "invalid_softchat_event",
262            Self::SoftchatEventCreationFailed => "softchat_event_creation_failed",
263            Self::InvalidSoftchatProjection => "invalid_softchat_projection",
264            Self::InvalidUserMetadata => "invalid_user_metadata",
265            Self::InvalidContactList => "invalid_contact_list",
266            Self::InvalidApplicationData => "invalid_application_data",
267            Self::InvalidRelaySession => "invalid_relay_session",
268            Self::RelaySessionQueueFull => "relay_session_queue_full",
269            Self::InvalidDeliveryState => "invalid_delivery_state",
270            Self::InvalidPersistenceResult => "invalid_persistence_result",
271            Self::InvalidAccountOperation => "invalid_account_operation",
272            Self::CommandConflict => "command_conflict",
273            Self::AccountAlreadyOpen => "account_already_open",
274            Self::AccountClosed => "account_closed",
275            Self::InvalidAccountSettings => "invalid_account_settings",
276            Self::InvalidMediaOperation => "invalid_media_operation",
277            Self::UnsupportedSystemAction => "unsupported_system_action",
278            Self::InvalidRelayCatalog => "invalid_relay_catalog",
279            Self::InvalidSyncState => "invalid_sync_state",
280            Self::InvalidNoiseHandshake => "invalid_noise_handshake",
281            Self::NoiseHandshakeConsumed => "noise_handshake_consumed",
282            Self::NoiseSessionClosed => "noise_session_closed",
283            Self::NoiseTransportFailed => "noise_transport_failed",
284            Self::InvalidNegentropy => "invalid_negentropy",
285            Self::EmptyPlaintext => "empty_plaintext",
286            Self::PlaintextTooLarge => "plaintext_too_large",
287            Self::InvalidEncryptedMessage => "invalid_encrypted_message",
288            Self::CiphertextTooLarge => "ciphertext_too_large",
289            Self::EncryptionFailed => "encryption_failed",
290            Self::DecryptionFailed => "decryption_failed",
291            Self::IdentityErased => "identity_erased",
292            Self::InternalFailure => "internal_failure",
293        }
294    }
295}