Skip to main content

kimberlite_storage/
error.rs

1//! Error types for storage operations.
2
3use std::io;
4
5use kimberlite_crypto::ChainHash;
6use kimberlite_types::Offset;
7
8/// Errors that can occur during storage operations.
9#[derive(thiserror::Error, Debug)]
10pub enum StorageError {
11    /// Generic write error.
12    #[error("error writing batch payload")]
13    WriteError,
14
15    /// Filesystem I/O error.
16    #[error("filesystem error: {0}")]
17    Io(#[from] io::Error),
18
19    /// The data was truncated (not enough bytes).
20    #[error("unexpected end of file")]
21    UnexpectedEof,
22
23    /// CRC mismatch - the record data is corrupted.
24    #[error("corrupted record: CRC mismatch")]
25    CorruptedRecord,
26
27    /// Torn write detected - record was incompletely written (AUDIT-2026-03 M-8).
28    ///
29    /// This occurs when power loss or crash happens during a write operation,
30    /// leaving a record with missing or corrupted sentinel markers.
31    #[error("torn write detected: {reason}")]
32    TornWrite { reason: String },
33
34    /// Invalid record kind byte.
35    #[error("invalid record kind byte {byte:#04x} at offset {offset}")]
36    InvalidRecordKind { byte: u8, offset: Offset },
37
38    /// Hash chain verification failed.
39    #[error(
40        "hash chain verification failed at offset {offset}: expected {expected:?}, found {actual:?}"
41    )]
42    ChainVerificationFailed {
43        offset: Offset,
44        expected: Option<ChainHash>,
45        actual: Option<ChainHash>,
46    },
47
48    /// Checkpoint payload is malformed.
49    #[error("invalid checkpoint payload at offset {offset}: {reason}")]
50    InvalidCheckpointPayload { offset: Offset, reason: String },
51
52    /// Index file has invalid magic bytes
53    #[error("invalid index magic bytes")]
54    InvalidIndexMagic,
55
56    /// Index file has unsupported version
57    #[error("unsupported index version: {0}")]
58    UnsupportedIndexVersion(u8),
59
60    /// Index file checksum mismatch
61    #[error("index checksum mismatch: expected {expected:#010x}, got {actual:#010x}")]
62    IndexChecksumMismatch { expected: u32, actual: u32 },
63
64    /// Index file is truncated
65    #[error("truncated index file: expected {expected} bytes, got {actual}")]
66    IndexTruncated { expected: usize, actual: usize },
67
68    /// Compression failed.
69    #[error("{codec} compression failed: {reason}")]
70    CompressionFailed { codec: &'static str, reason: String },
71
72    /// Decompression failed.
73    #[error("{codec} decompression failed: {reason}")]
74    DecompressionFailed { codec: &'static str, reason: String },
75
76    /// Invalid compression kind byte.
77    #[error("invalid compression kind byte {byte:#04x} at offset {offset}")]
78    InvalidCompressionKind { byte: u8, offset: Offset },
79}