Skip to main content

mail4agent_messenger/
error.rs

1//! [`MessengerError`], this crate's single error type.
2
3/// Every error this crate's public API can return. Sans-I/O by
4/// construction (see the crate doc): this type never itself performs I/O —
5/// it only describes a failure the caller (a shell, or another module in
6/// this crate) already observed.
7#[derive(Debug, thiserror::Error)]
8pub enum MessengerError {
9    /// One of the identifier newtypes in [`crate::ids`] rejected a value.
10    #[error("invalid {kind} {value:?}: {reason}")]
11    InvalidId {
12        /// The newtype that rejected the value (`"UserId"`, `"RoomId"`, …).
13        kind: &'static str,
14        /// The rejected input, verbatim.
15        value: String,
16        /// Why it was rejected.
17        reason: String,
18    },
19
20    /// A wire payload (an HTTP response body, a `/sync` response, …) was
21    /// not valid JSON, or did not match the shape this crate expected of
22    /// it.
23    #[error("failed to decode wire JSON: {0}")]
24    WireDecode(#[from] serde_json::Error),
25
26    /// An HTTP response came back with an error status and a Matrix-shaped
27    /// `{"errcode": ..., "error": ...}` body (client-server API's own
28    /// standard error response shape).
29    #[error("HTTP {status} {errcode}: {error}")]
30    Http {
31        /// The HTTP status code.
32        status: u16,
33        /// The Matrix `errcode` (e.g. `"M_FORBIDDEN"`).
34        errcode: String,
35        /// The Matrix `error` human-readable string.
36        error: String,
37    },
38
39    /// A cryptographic operation (Olm/Megolm/SAS via `mail4agent_vodozemac`,
40    /// or the local record seal) failed. Wrapped as a plain message rather
41    /// than the concrete upstream error type: this crate's own public API
42    /// must not leak `mail4agent_vodozemac`'s error enum shape as part of
43    /// its own contract.
44    #[error("crypto: {0}")]
45    Crypto(String),
46
47    /// A [`crate::store::CryptoStore`]/[`crate::store::StateStore`]
48    /// operation failed.
49    #[error("store: {0}")]
50    Store(#[from] crate::store::StoreError),
51
52    /// Raised when a caller (`crate::outgoing_queue`/a later `sync_engine`
53    /// piece) attempts to release an outgoing request while
54    /// [`crate::persist::FlushEpoch::is_released`] reports it is not yet
55    /// safe to do so — a state mutation the request depends on is not yet
56    /// durably flushed and acknowledged. See the `persist` module doc for
57    /// the exact per-request ordering guarantee this enforces.
58    #[error(
59        "outgoing requests are blocked: a state mutation they depend on is not yet flushed and acknowledged"
60    )]
61    FlushPending,
62
63    /// [`crate::MessengerCommand::SendMessage`] named an `edit_of` target
64    /// this account did not itself send (or that this core has never seen
65    /// at all) — rejected outright by [`crate::MessengerCore::dispatch`]
66    /// rather than silently sent as a replacement every other member's own
67    /// `m.replace` aggregation would ignore anyway
68    /// (`crate::room::relations`'s own module doc: "must come from the
69    /// original sender").
70    #[error("cannot edit {event_id}: not sent by this account, or unknown")]
71    EditNotOwned {
72        /// The event the caller tried to edit.
73        event_id: crate::ids::EventId,
74    },
75
76    /// A [`crate::MessengerCommand`] the core refused to apply. The message
77    /// names the command and the reason (an unknown room, a sealed event, ...).
78    #[error("intent refused: {0}")]
79    IntentRefused(String),
80}
81
82impl From<crate::canonical_json::CanonicalJsonError> for MessengerError {
83    /// [`crate::canonical_json`] is its own small, dependency-light module
84    /// (it only needs `mail4agent_vodozemac`'s signature types, not this crate's
85    /// error type) -- this conversion is what lets `crypto::account` and
86    /// later pieces use `?` against it without that module needing to know
87    /// about [`MessengerError`] itself.
88    fn from(err: crate::canonical_json::CanonicalJsonError) -> Self {
89        MessengerError::Crypto(format!("canonical JSON: {err}"))
90    }
91}