Skip to main content

nautilus_event_store/
error.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Error types for the event store.
17
18use thiserror::Error;
19
20/// Errors returned by event store backends, the writer, the reader, and the verifier.
21///
22/// The variants form a typed surface for the operational policies described in the SPEC: disk
23/// pressure halts the kernel, hash mismatch quarantines the affected run, and a crashed
24/// predecessor is sealed by the caller before a new run is opened.
25#[derive(Debug, Error)]
26pub enum EventStoreError {
27    /// A backend operation failed for a reason that does not fit any other variant.
28    ///
29    /// Typically wraps a redb error or an in-memory backend invariant violation.
30    #[error("backend error: {0}")]
31    Backend(String),
32    /// A run file is structurally damaged and cannot be opened safely.
33    ///
34    /// Surfaces redb header-region corruption and any backend-detected structural failure.
35    #[error("corrupted run: {0}")]
36    Corrupted(String),
37    /// The backing storage refused the write because of disk pressure.
38    ///
39    /// Maps to redb `Io(FileTooLarge)` and equivalent host-level failures (ENOSPC,
40    /// `RLIMIT_FSIZE`). Triggers the kernel halt path; the writer fail-stops.
41    #[error("disk error: {0}")]
42    Disk(String),
43    /// The canonical entry hash recorded with a row does not match the recomputed hash.
44    ///
45    /// Quarantines the affected run.
46    #[error("entry hash mismatch at seq {seq}")]
47    HashMismatch {
48        /// The sequence number whose stored hash did not match.
49        seq: u64,
50    },
51    /// The writer received an entry whose sequence number is not contiguous after the
52    /// current durable high-watermark.
53    #[error(
54        "out-of-order seq: received {seq}, expected contiguous after high-watermark {high_watermark}"
55    )]
56    OutOfOrder {
57        /// The current durable high-watermark.
58        high_watermark: u64,
59        /// The offending sequence number.
60        seq: u64,
61    },
62    /// The run is sealed and cannot accept further writes.
63    #[error("run is closed")]
64    Closed,
65    /// A reader processing `seq=N+1` did not observe `seq=N`.
66    ///
67    /// One of the four idempotency primitives: gap detection on read.
68    #[error("gap detected: missing seq {missing} between {prev} and {next}")]
69    Gap {
70        /// The last seq the reader observed.
71        prev: u64,
72        /// The next seq the reader observed.
73        next: u64,
74        /// The first missing seq.
75        missing: u64,
76    },
77    /// Opening a run found a predecessor whose status is `Running` and that lacks a
78    /// `RunEnded` entry.
79    ///
80    /// The kernel is expected to seal the predecessor (as `CrashedRecovered`, or
81    /// `Quarantined` if hash check fails) and then open a new run that records the
82    /// predecessor's `run_id` as `parent_run_id`.
83    #[error("crashed predecessor run requires sealing")]
84    CrashedPredecessor,
85}