Skip to main content

reddb_engine/storage/
error.rs

1//! Canonical storage errors shared by native and browser hosts.
2use super::entity::EntityId;
3use super::segment::SegmentError;
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct StorageIntegrityError {
8    pub zone: String,
9    pub id: String,
10    pub collection: Option<String>,
11    pub detail: String,
12}
13
14impl StorageIntegrityError {
15    pub fn new(
16        zone: impl Into<String>,
17        id: impl Into<String>,
18        collection: Option<String>,
19        detail: impl Into<String>,
20    ) -> Self {
21        Self {
22            zone: zone.into(),
23            id: id.into(),
24            collection,
25            detail: detail.into(),
26        }
27    }
28}
29
30impl fmt::Display for StorageIntegrityError {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        write!(
33            f,
34            "storage integrity failure: zone={} id={}",
35            self.zone, self.id
36        )?;
37        if let Some(collection) = &self.collection {
38            write!(f, " collection={collection}")?;
39        }
40        write!(
41            f,
42            ": {}. RedDB refused to serve unverified bytes; run the `SCRUB` statement to classify the fault, or `red salvage` to recover trusted rows.",
43            self.detail
44        )
45    }
46}
47
48/// Errors from UnifiedStore operations
49#[derive(Debug)]
50pub enum StoreError {
51    /// Collection already exists
52    CollectionExists(String),
53    /// Collection not found
54    CollectionNotFound(String),
55    /// Entity not found
56    EntityNotFound(EntityId),
57    /// Too many cross-references
58    TooManyRefs(EntityId),
59    /// Segment error
60    Segment(SegmentError),
61    /// I/O error
62    Io(std::io::Error),
63    /// Checksummed storage bytes failed validation.
64    StorageIntegrity(StorageIntegrityError),
65    /// Serialization error
66    Serialization(String),
67    /// A read must be rejected before allocating beyond its allowance.
68    ReadLimitExceeded {
69        required_bytes: usize,
70        limit_bytes: usize,
71    },
72    /// Internal error (lock poisoning, invariant violation)
73    Internal(String),
74}
75
76impl std::fmt::Display for StoreError {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        match self {
79            Self::CollectionExists(name) => write!(f, "Collection already exists: {}", name),
80            Self::CollectionNotFound(name) => write!(f, "Collection not found: {}", name),
81            Self::EntityNotFound(id) => write!(f, "Entity not found: {}", id),
82            Self::TooManyRefs(id) => write!(f, "Too many cross-references for entity: {}", id),
83            Self::Segment(e) => write!(f, "Segment error: {:?}", e),
84            Self::Io(e) => write!(f, "I/O error: {}", e),
85            Self::StorageIntegrity(e) => write!(f, "{e}"),
86            Self::Serialization(msg) => write!(f, "Serialization error: {}", msg),
87            Self::ReadLimitExceeded {
88                required_bytes,
89                limit_bytes,
90            } => write!(
91                f,
92                "read needs {required_bytes} bytes over read memory limit {limit_bytes}"
93            ),
94            Self::Internal(msg) => write!(f, "Internal error: {}", msg),
95        }
96    }
97}
98
99impl std::error::Error for StoreError {}
100
101impl From<SegmentError> for StoreError {
102    fn from(e: SegmentError) -> Self {
103        Self::Segment(e)
104    }
105}
106
107impl From<std::io::Error> for StoreError {
108    fn from(e: std::io::Error) -> Self {
109        Self::Io(e)
110    }
111}