Skip to main content

nodedb_types/error/
code.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Stable numeric error codes for programmatic error handling.
4
5use std::fmt;
6
7use serde::{Deserialize, Serialize};
8
9/// Stable numeric error codes for programmatic error handling.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub struct ErrorCode(pub u16);
12
13impl ErrorCode {
14    // Write path (1000–1099)
15    pub const CONSTRAINT_VIOLATION: Self = Self(1000);
16    pub const WRITE_CONFLICT: Self = Self(1001);
17    pub const DEADLINE_EXCEEDED: Self = Self(1002);
18    pub const PREVALIDATION_REJECTED: Self = Self(1003);
19    pub const APPEND_ONLY_VIOLATION: Self = Self(1010);
20    pub const BALANCE_VIOLATION: Self = Self(1011);
21    pub const PERIOD_LOCKED: Self = Self(1012);
22    pub const STATE_TRANSITION_VIOLATION: Self = Self(1013);
23    pub const TRANSITION_CHECK_VIOLATION: Self = Self(1014);
24    pub const RETENTION_VIOLATION: Self = Self(1015);
25    pub const LEGAL_HOLD_ACTIVE: Self = Self(1016);
26    pub const TYPE_MISMATCH: Self = Self(1020);
27    pub const OVERFLOW: Self = Self(1021);
28    pub const INSUFFICIENT_BALANCE: Self = Self(1022);
29    pub const RATE_EXCEEDED: Self = Self(1023);
30    pub const TYPE_GUARD_VIOLATION: Self = Self(1024);
31
32    // Read path (1100–1199)
33    pub const COLLECTION_NOT_FOUND: Self = Self(1100);
34    pub const DOCUMENT_NOT_FOUND: Self = Self(1101);
35    pub const COLLECTION_DRAINING: Self = Self(1102);
36    pub const COLLECTION_DEACTIVATED: Self = Self(1103);
37    /// The named database does not exist.
38    pub const DATABASE_NOT_FOUND: Self = Self(1110);
39    /// Attempted to drop the built-in `default` database, which is immutable.
40    pub const CANNOT_DROP_DEFAULT_DATABASE: Self = Self(1111);
41
42    // Query (1200–1299)
43    pub const PLAN_ERROR: Self = Self(1200);
44    pub const FAN_OUT_EXCEEDED: Self = Self(1201);
45    pub const SQL_NOT_ENABLED: Self = Self(1202);
46
47    // Engine ops (1300–1399)
48    pub const ARRAY: Self = Self(1300);
49
50    // Quota (1400–1499)
51
52    /// The proposed quota allocation would push the sum of all database quotas
53    /// past the configured global ceiling, or the sum of all tenant quotas past
54    /// the database ceiling.
55    pub const QUOTA_OVERCOMMIT: Self = Self(1400);
56    /// A request was rejected because the calling tenant has exhausted its quota
57    /// (QPS, memory, connections, or storage).
58    pub const TENANT_QUOTA_EXCEEDED: Self = Self(1401);
59    /// A request was rejected because the target database has exhausted its quota.
60    pub const DATABASE_QUOTA_EXCEEDED: Self = Self(1402);
61    /// The server is under global resource pressure and cannot accept new requests.
62    pub const SERVER_OVERLOAD: Self = Self(1403);
63
64    // Clone (1500–1599)
65
66    /// A `CLONE DATABASE` would exceed the maximum clone chain depth of 8.
67    pub const CLONE_DEPTH_EXCEEDED: Self = Self(1500);
68    /// A mirror database cannot be cloned; promote the mirror first.
69    pub const CANNOT_CLONE_MIRROR: Self = Self(1501);
70    /// The source database cannot be dropped while clones depend on it.
71    pub const CLONE_DEPENDENCY: Self = Self(1502);
72    /// A bitemporal `AS OF` query timestamp predates the clone's creation LSN.
73    pub const CLONE_PREDATES_QUERY_TIME: Self = Self(1503);
74
75    // Mirror (1700–1799)
76
77    /// Write attempted on a mirror database that has not yet been promoted.
78    pub const MIRROR_READ_ONLY: Self = Self(1700);
79    /// Strong consistency read requested on a mirror; mirrors cannot serve
80    /// strong reads. The client should retry against the source cluster.
81    pub const STALE_READ_NOT_LEADER: Self = Self(1701);
82    /// Operation requires the mirror to be promoted, but it has not been.
83    pub const MIRROR_NOT_PROMOTED: Self = Self(1702);
84
85    // Move Tenant (1600–1699)
86
87    /// `MOVE TENANT` drain phase timed out; source left unchanged.
88    pub const MOVE_TENANT_DRAIN_TIMEOUT: Self = Self(1600);
89    /// `MOVE TENANT` pre-flight failed; collection schema incompatibility.
90    pub const MOVE_TENANT_PREFLIGHT_FAILED: Self = Self(1601);
91    /// `MOVE TENANT` snapshot phase failed; source left unchanged.
92    pub const MOVE_TENANT_SNAPSHOT_FAILED: Self = Self(1602);
93    /// `MOVE TENANT` cutover phase failed; source still holds the data.
94    pub const MOVE_TENANT_CUTOVER_FAILED: Self = Self(1603);
95    /// Tenant is already at the target database; `MOVE TENANT` was a no-op.
96    pub const MOVE_TENANT_ALREADY_AT_TARGET: Self = Self(1604);
97
98    // Auth / Security (2000–2099)
99    pub const AUTHORIZATION_DENIED: Self = Self(2000);
100    pub const AUTH_EXPIRED: Self = Self(2001);
101    /// Vector insert or index rejected because the vector dimension exceeds the
102    /// tenant's `max_vector_dim` quota.
103    pub const TENANT_VECTOR_DIM_EXCEEDED: Self = Self(2010);
104    /// Graph traversal rejected because the requested depth exceeds the tenant's
105    /// `max_graph_depth` quota.
106    pub const TENANT_GRAPH_DEPTH_EXCEEDED: Self = Self(2011);
107
108    // Protocol handshake (2100–2199)
109    pub const HANDSHAKE_FAILED: Self = Self(2100);
110
111    // Sync (3000–3099)
112    pub const SYNC_CONNECTION_FAILED: Self = Self(3000);
113    pub const SYNC_DELTA_REJECTED: Self = Self(3001);
114    pub const SHAPE_SUBSCRIPTION_FAILED: Self = Self(3002);
115
116    // Storage (4000–4099)
117    pub const STORAGE: Self = Self(4000);
118    pub const SEGMENT_CORRUPTED: Self = Self(4001);
119    pub const COLD_STORAGE: Self = Self(4002);
120
121    // WAL (4100–4199)
122    pub const WAL: Self = Self(4100);
123
124    // Serialization (4200–4299)
125    pub const SERIALIZATION: Self = Self(4200);
126    pub const CODEC: Self = Self(4201);
127
128    // Config (5000–5099)
129    pub const CONFIG: Self = Self(5000);
130    pub const BAD_REQUEST: Self = Self(5001);
131
132    // Cluster (6000–6099)
133    pub const NO_LEADER: Self = Self(6000);
134    pub const NOT_LEADER: Self = Self(6001);
135    pub const MIGRATION_IN_PROGRESS: Self = Self(6002);
136    pub const NODE_UNREACHABLE: Self = Self(6003);
137    pub const CLUSTER: Self = Self(6010);
138
139    // Memory (7000–7099)
140    pub const MEMORY_EXHAUSTED: Self = Self(7000);
141
142    // Encryption (8000–8099)
143    pub const ENCRYPTION: Self = Self(8000);
144
145    // Internal (9000–9099)
146    pub const INTERNAL: Self = Self(9000);
147    pub const BRIDGE: Self = Self(9001);
148    pub const DISPATCH: Self = Self(9002);
149}
150
151impl fmt::Display for ErrorCode {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        write!(f, "NDB-{:04}", self.0)
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn error_code_display() {
163        assert_eq!(ErrorCode::CONSTRAINT_VIOLATION.to_string(), "NDB-1000");
164        assert_eq!(ErrorCode::INTERNAL.to_string(), "NDB-9000");
165        assert_eq!(ErrorCode::WAL.to_string(), "NDB-4100");
166    }
167}