Skip to main content

katra_core/
error.rs

1//! The Katra error model.
2//!
3//! Errors are **categories**, not strings. Every failure mode maps to one
4//! category so that policy code (fallback, promotion gates, budgets) can
5//! switch on the category without parsing messages.
6//!
7//! See `docs/standards/error-model.md` for the full policy.
8
9use std::fmt;
10
11/// Result alias used across Katra3D.
12pub type Result<T, E = KatraError> = core::result::Result<T, E>;
13
14/// Coarse error category. Policy decisions must only depend on this, never
15/// on the human-readable message.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum ErrorCategory {
18    /// A caller passed an invalid argument.
19    InvalidArgument,
20    /// The requested operation is not supported in this build/backend.
21    NotSupported,
22    /// A budget (memory, bandwidth, ring depth, ...) was exceeded.
23    OutOfBudget,
24    /// An I/O operation failed.
25    Io,
26    /// A protocol/serialization violation (trace format, message framing).
27    Protocol,
28    /// A resource was not found.
29    NotFound,
30    /// A resource already exists.
31    AlreadyExists,
32    /// Data is corrupt (cache index, trace, archive).
33    Corrupt,
34    /// An operation timed out.
35    Timeout,
36    /// A synchronization invariant was violated.
37    Sync,
38    /// A fallback implementation was requested but is unavailable.
39    FallbackUnavailable,
40    /// An internal invariant was violated (a Katra bug).
41    Internal,
42}
43
44/// The unified Katra error type.
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum KatraError {
47    /// Invalid argument; the `&'static str` names the argument.
48    InvalidArgument(&'static str),
49    /// Operation not supported; the message names the capability.
50    NotSupported(String),
51    /// A budget was exceeded.
52    OutOfBudget {
53        /// Budget name, e.g. `"staging_bytes"`.
54        resource: &'static str,
55        /// Amount requested.
56        requested: u64,
57        /// Amount available.
58        available: u64,
59    },
60    /// I/O failure.
61    Io(std::io::ErrorKind, String),
62    /// Protocol violation (trace format, ABI framing).
63    Protocol(String),
64    /// Resource not found.
65    NotFound(String),
66    /// Resource already exists.
67    AlreadyExists(String),
68    /// Corrupt data.
69    Corrupt(String),
70    /// Timeout.
71    Timeout {
72        /// What timed out.
73        what: &'static str,
74        /// Timeout in nanoseconds.
75        timeout_ns: u64,
76    },
77    /// Synchronization invariant violation.
78    Sync(String),
79    /// Fallback unavailable.
80    FallbackUnavailable(&'static str),
81    /// Internal invariant violation.
82    Internal(&'static str),
83}
84
85impl KatraError {
86    /// The coarse category of this error.
87    pub fn category(&self) -> ErrorCategory {
88        match self {
89            KatraError::InvalidArgument(_) => ErrorCategory::InvalidArgument,
90            KatraError::NotSupported(_) => ErrorCategory::NotSupported,
91            KatraError::OutOfBudget { .. } => ErrorCategory::OutOfBudget,
92            KatraError::Io(..) => ErrorCategory::Io,
93            KatraError::Protocol(_) => ErrorCategory::Protocol,
94            KatraError::NotFound(_) => ErrorCategory::NotFound,
95            KatraError::AlreadyExists(_) => ErrorCategory::AlreadyExists,
96            KatraError::Corrupt(_) => ErrorCategory::Corrupt,
97            KatraError::Timeout { .. } => ErrorCategory::Timeout,
98            KatraError::Sync(_) => ErrorCategory::Sync,
99            KatraError::FallbackUnavailable(_) => ErrorCategory::FallbackUnavailable,
100            KatraError::Internal(_) => ErrorCategory::Internal,
101        }
102    }
103}
104
105impl fmt::Display for KatraError {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        match self {
108            KatraError::InvalidArgument(a) => write!(f, "invalid argument: {a}"),
109            KatraError::NotSupported(c) => write!(f, "not supported: {c}"),
110            KatraError::OutOfBudget { resource, requested, available } => write!(
111                f,
112                "budget exceeded for {resource}: requested {requested}, available {available}"
113            ),
114            KatraError::Io(kind, msg) => write!(f, "io error ({kind}): {msg}"),
115            KatraError::Protocol(msg) => write!(f, "protocol violation: {msg}"),
116            KatraError::NotFound(msg) => write!(f, "not found: {msg}"),
117            KatraError::AlreadyExists(msg) => write!(f, "already exists: {msg}"),
118            KatraError::Corrupt(msg) => write!(f, "corrupt data: {msg}"),
119            KatraError::Timeout { what, timeout_ns } => {
120                write!(f, "timeout on {what} after {timeout_ns} ns")
121            }
122            KatraError::Sync(msg) => write!(f, "synchronization violation: {msg}"),
123            KatraError::FallbackUnavailable(s) => write!(f, "fallback unavailable: {s}"),
124            KatraError::Internal(msg) => write!(f, "internal error: {msg}"),
125        }
126    }
127}
128
129impl std::error::Error for KatraError {}
130
131impl From<std::io::Error> for KatraError {
132    fn from(e: std::io::Error) -> Self {
133        KatraError::Io(e.kind(), e.to_string())
134    }
135}