Skip to main content

nodedb_cluster/mirror/
error.rs

1// SPDX-License-Identifier: BUSL-1.1
2
3//! Error types for cross-cluster mirror transport and bootstrap.
4
5use thiserror::Error;
6
7/// Errors produced by cross-cluster mirror operations.
8///
9/// These wrap into [`crate::error::ClusterError::Mirror`] at the public
10/// boundary so callers have a single error type to handle.
11#[derive(Debug, Error)]
12pub enum MirrorError {
13    /// The remote cluster refused our connection because the `source_cluster`
14    /// we declared does not match their own cluster id.
15    #[error(
16        "cluster-id mismatch: we declared source_cluster={declared:?}, \
17         remote reports its id as {remote:?}"
18    )]
19    ClusterIdMismatch { declared: String, remote: String },
20
21    /// The remote cluster rejected the mirror link because the connecting
22    /// peer presented `Observer` role credentials but tried to perform a
23    /// voter operation (vote request, conf change, etc.).
24    #[error("observer-role violation: peer attempted voter operation: {detail}")]
25    ObserverRoleViolation { detail: String },
26
27    /// Snapshot transfer was aborted because a chunk arrived out of order.
28    ///
29    /// The receiver resets and requests a fresh snapshot from the source.
30    #[error(
31        "snapshot offset regression for database {database_id:?}: \
32         expected {expected}, got {actual}"
33    )]
34    SnapshotOffsetRegression {
35        database_id: String,
36        expected: u64,
37        actual: u64,
38    },
39
40    /// Snapshot CRC validation failed at the final chunk.
41    #[error(
42        "snapshot CRC mismatch for database {database_id:?}: \
43         stored {stored:#010x}, computed {computed:#010x}"
44    )]
45    SnapshotCrcMismatch {
46        database_id: String,
47        stored: u32,
48        computed: u32,
49    },
50
51    /// The cross-cluster handshake wire message could not be decoded.
52    #[error("cross-cluster handshake codec error: {detail}")]
53    HandshakeCodec { detail: String },
54
55    /// The mirror declared a wire protocol version the source does not
56    /// implement (or vice versa).  Surfaced immediately without retry — the
57    /// peers must be upgraded in lockstep.
58    #[error("cross-cluster protocol version mismatch: local={local}, remote_detail={detail:?}")]
59    ProtocolVersionMismatch { local: u16, detail: String },
60
61    /// QUIC transport error during cross-cluster operations.
62    #[error("cross-cluster transport error: {detail}")]
63    Transport { detail: String },
64
65    /// Observer-side bytes-in-flight cap was exceeded; the source should
66    /// pause sending until the observer drains.
67    #[error(
68        "bytes-in-flight cap exceeded: in_flight={in_flight}, cap={cap} for mirror {database_id:?}"
69    )]
70    BytesInFlightCapExceeded {
71        database_id: String,
72        in_flight: u64,
73        cap: u64,
74    },
75
76    /// The mirror is in `Promoted` state and can no longer accept replication.
77    #[error("mirror {database_id:?} is promoted and no longer accepts replication")]
78    MirrorPromoted { database_id: String },
79}