#[non_exhaustive]pub enum Error {
Show 30 variants
Io(Error),
Decompress(CompressionType),
InvalidVersion(u8),
Unrecoverable,
ChecksumMismatch {
got: Checksum,
expected: Checksum,
},
MemtableKvChecksumMismatch {
seqno: u64,
got: u64,
expected: u64,
},
MemtableKvChecksumCorruptAlgorithm {
seqno: u64,
tag: u8,
},
HeaderCrcMismatch {
recomputed: u32,
stored: u32,
},
InvalidTag((&'static str, u8)),
InvalidTrailer,
InvalidHeader(&'static str),
DecompressedSizeTooLarge {
declared: u64,
limit: u64,
},
Utf8(Utf8Error),
MergeOperator,
Encrypt(&'static str),
Decrypt(&'static str),
ComparatorMismatch {
stored: String,
supplied: &'static str,
},
ZstdDictMismatch {
expected: u32,
got: Option<u32>,
},
ManifestFrameChecksumMismatch {
section: &'static str,
expected: u64,
got: u64,
},
RangeTombstoneDecode {
field: &'static str,
offset: u64,
},
MixedOperationBatch,
PageEccUnsupported,
PageEccUnrecoverable {
got: Checksum,
expected: Checksum,
},
RouteMismatch {
expected: usize,
found: usize,
},
FeatureUnsupported(&'static str),
Locked(String),
ManifestFooterInvalid(&'static str),
ManifestSectionInvalid(&'static str),
TornManifestEditLog {
kind: &'static str,
},
StorageFull {
used: u64,
limit: u64,
},
}Expand description
Represents errors that can occur in the LSM-tree
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Io(Error)
I/O error
Decompress(CompressionType)
Decompression failed
InvalidVersion(u8)
Invalid or unparsable data format version
Unrecoverable
Some required files could not be recovered from disk
ChecksumMismatch
Checksum mismatch
Fields
got: ChecksumChecksum of loaded block
expected: ChecksumChecksum that was saved in block header
MemtableKvChecksumMismatch
A memtable entry’s per-KV digest, computed at insert under
KvChecksumComputePoint::AtInsert,
did not match a recompute over the entry’s current bytes at flush.
This is the memtable-residence RAM-corruption signal: the entry’s
logical content (value_type, seqno, key, or value) changed while it
sat in the memtable, between insert and flush. Distinct from
Self::ChecksumMismatch (on-disk block bytes) — this catches a flip
that happens entirely in RAM, before any block is written.
Fields
MemtableKvChecksumCorruptAlgorithm
A memtable entry carried an insert-time per-KV digest
(KvChecksumComputePoint::AtInsert)
tagged with an algorithm AtInsert never stores: a non-4-byte or
unknown algorithm wire tag.
AtInsert only ever writes a 4-byte algorithm tag (Xxh3Low32 /
Crc32c), so a digest-bearing node tagged otherwise means the node’s
algorithm metadata was corrupted in RAM during memtable residence.
Distinct from Self::MemtableKvChecksumMismatch (the digest value
diverged): here the algorithm itself is unusable, so the engine refuses
to “verify” the entry under the wrong algorithm rather than risk a
flipped tag passing the residence check.
Fields
HeaderCrcMismatch
Blob frame header CRC mismatch (V4 format).
Distinct from ChecksumMismatch which covers data payload checksums.
Fields
InvalidTag((&'static str, u8))
Invalid enum tag
InvalidTrailer
Invalid block trailer
InvalidHeader(&'static str)
Invalid block header
DecompressedSizeTooLarge
Data size (decompressed, on-disk, or requested) is invalid or exceeds a safety limit
Fields
Utf8(Utf8Error)
UTF-8 error
MergeOperator
Merge operator failed.
No context payload — consistent with other unit variants
(Unrecoverable, InvalidTrailer). Operators should log
details before returning this error.
Encrypt(&'static str)
Encryption failed
Decrypt(&'static str)
Decryption failed
ComparatorMismatch
Comparator mismatch on tree reopen.
The tree was created with a comparator whose crate::UserComparator::name
differs from the one supplied at reopen time.
Fields
ZstdDictMismatch
Zstd dictionary required but not provided, or dict_id mismatch
Fields
ManifestFrameChecksumMismatch
Per-record XXH3-64 mismatch inside a framed manifest section
(tables / blob_files). Distinct from
Error::ChecksumMismatch — same XXH3 family but a
different output width (XXH3-64 here vs XXH3-128 for
block-level payloads) on a different layer of the on-disk
format, with different recovery semantics (manifest framing
surfaces routed through ManifestRecoveryMode; block
checksums surface via Error::ChecksumMismatch for the
block I/O paths). Strict manifest recovery modes surface
this so an operator can see the exact 64-bit digests that
disagreed; SkipAnyCorruptedRecords and
PointInTimeRecovery route around the corruption without
raising it.
Fields
RangeTombstoneDecode
Range tombstone block decode failure.
Fields
MixedOperationBatch
A WriteBatch contains mixed operation types
(e.g. insert + remove) for the same user key.
Mixed ops at the same logical version are rejected because the
memtable/skiplist ordering ties on (user_key, seqno) and does not
include value_type as a tie-breaker. That would otherwise make
equal-key entries with different operation types ambiguous to later
reads and merges, yielding tie-break-dependent “last write wins”
semantics.
PageEccUnsupported
Tree was opened with Config::page_ecc(true) but this build of
the crate does not have the page_ecc cargo feature enabled.
The reader has no way to verify or recover Reed-Solomon parity
without the codec, so opening such a tree would silently
downgrade integrity guarantees — return this error instead.
PageEccUnrecoverable
Block payload failed the XXH3 integrity check and the
attached Reed-Solomon parity trailer could not reconstruct
it (more shards are corrupted than the (4, 2) RS scheme
can recover). Surfaced ONLY by ECC-protected blocks
(the ECC_PARITY header flag set); a block written without parity
(Config::page_ecc(false)) on a checksum mismatch returns
Self::ChecksumMismatch instead, because there’s no
parity to even attempt recovery from.
Fields
got: ChecksumXXH3 checksum recomputed from the on-disk bytes.
expected: ChecksumXXH3 checksum stored in the block header.
RouteMismatch
Route-compatibility mismatch on reopen.
Recovery found fewer tables on disk than the manifest expects, and all
missing tables are on levels not covered by any current
level_routes. This typically means a
previously configured route was removed, leaving its directory
unreachable.
Re-adding the missing route(s) will usually resolve the error. If
missing tables are on levels that are covered by a current route,
recovery returns Unrecoverable instead
(the SST files were genuinely lost).
Fields
FeatureUnsupported(&'static str)
Valid configuration / on-disk layout that this build does not
yet know how to process, or constructor input that violates a
documented invariant (e.g. CompressionType::None passed to
[crate::table::block::CompressionContext::new]). Distinct
from Error::Unrecoverable (signals corruption) and from
Error::Io with ErrorKind::Unsupported (which can also
surface from platform / backend limits); the &'static str
payload names the specific marker that triggered the rejection
(e.g. "filter_tli" for a partitioned filter SFA section,
"compression-context-none" for the constructor invariant) so
the caller can route the diagnostic without parsing message
strings.
Locked(String)
The tree directory is already locked by another live instance.
Returned by Config::open and
Config::repair when the cross-process
directory lock (a LOCK file under the tree directory, held via an
advisory OS file lock) could not be acquired because another process
owns it. Holds the directory path as a display string for diagnostics.
Two processes mutating the same manifest would corrupt it, so the second
acquirer fails fast here. Disable the lock with
Config::with_directory_lock only
when exclusivity is enforced at a higher layer.
Manifest footer / TOC / file-level discovery failure.
Scoped to errors detected at or before the TOC is parsed —
i.e. everything the reader needs before it can answer
“where is section X”. Section-content failures (a specific
section’s Block fails verification) go through
ManifestSectionInvalid
instead so callers like Tree::open can distinguish a
totally unreadable manifest from a per-section problem.
Typical causes:
- Footer-payload structural failure: unknown layout version, oversized section count, empty/oversized section name, invalid UTF-8, duplicate section name, footer payload exceeds the 4 KiB reservation.
- Tail / head-mirror double failure: both the
tail-footer Block read and the head-mirror fallback
failed verification (XXH3 mismatch, AEAD decryption,
parse error). Per-path causes are logged at
errorlevel and collapsed here. - TOC entry value corruption: a TOC entry’s
block_offset + block_sizeoverflowsu64or extends past the end of the file. The TOC bytes are footer payload, so a malformed TOC entry is a footer-level issue even though it surfaces inManifestArchiveReader::read_section. - Trailing size-hint corruption: the tail’s 4-byte
footer-size hint is zero or exceeds
HEAD_FOOTER_RESERVED_SIZE(4 KiB), or the impliedsection_endlands inside the head reservation. Caught in both the reader andcheckpoint::write_current_for_version. - Writer-side invariant breach:
write_cursorwould overflowu64, an in-memory section would exceed the on-disk Block-size cap, etc. - CURRENT pointer points at a missing manifest: when
version::get_current_versionopens the referencedv{N}file and getsNotFound, the error is rewrapped here soTree::open’s outerIo(NotFound) => create_newarm cannot mistake a half-applied recovery / corrupted state for a clean first-open.
ManifestSectionInvalid(&'static str)
Manifest section content failed verification or matched no TOC entry.
Surfaced by ManifestArchiveReader::read_section (and the
helper that validates the inner Block header before
delegating to Block::from_reader). Distinct from
ManifestFooterInvalid
because the footer / TOC loaded fine — the bad bytes are
localised to one section Block and a caller MAY route
recovery differently (e.g. skip the section vs. refuse
the whole manifest).
Causes:
- Requested section name not in TOC: the caller asked for a section that the manifest doesn’t declare.
- Section Block header doesn’t fit its outer buffer:
the inner block’s derived on-disk size (header + payload +
parity-if-flagged) exceeds the TOC-declared
block_size. Defence-in-depth against a forged TOC pointing at a too-small slot. - Block decoded at the TOC offset has the wrong
block_type: TOC says “section here” but the bytes carry a non-ManifestBlock. Defence-in-depth against TOC-redirect attacks; once AAD-binding lands inencryption::block,Block::from_readerwill reject this internally and the check here becomes belt-and- braces.
TornManifestEditLog
The trailing record of the incremental manifest edit log is
incomplete or corrupt, and the active
ManifestRecoveryMode does
not tolerate that defect, so the open aborts rather than silently
rolling the edit back.
A clean end-of-log is never reported here: a crash exactly at a
record boundary is byte-identical to a pristine close, so that
case is always tolerated. This fires when bytes of a trailing
record are present but the record fails framing — a
power-loss-truncated append (only
AbsoluteConsistency
rejects it; other modes roll it back), or a fully-framed record
whose checksum doesn’t match (bit-rot) / whose header is forged
(rejected by both AbsoluteConsistency and
TolerateCorruptedTailRecords,
which salvages writer-incomplete tails only; rolled back under
PointInTimeRecovery / SkipAnyCorruptedRecords).
Recover by truncating the torn tail: run
Config::repair, which rebuilds a clean
standalone snapshot (dropping the edit log), or re-open under a
ManifestRecoveryMode that
tolerates the defect to roll the trailing edit back.
Fields
kind: &'static strThe trailing defect detected: "truncated" (partial record
from a power-loss-interrupted append), "checksum-mismatch"
(fully-framed record whose payload bit-rotted),
"bad-header" (implausible framing length), or
"len-mismatch" (record length disagrees with the expected
fixed size). Static so callers can branch without parsing
the message string.
StorageFull
A write was declined by the storage admission gate because accepting it could push the tree’s live footprint past its effective budget.
Only produced when storage_admission_check
is enabled. The predicate is computed, not latched: raising
storage_limit_bytes,
freeing disk, or a compaction reclaiming space clears the read-only
state on the next check with no restart. Internal flush / compaction are
never gated (reserved headroom), so the engine can always reclaim space.
Trait Implementations§
Source§impl Error for Error
impl Error for Error
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Auto Trait Implementations§
impl Freeze for Error
impl RefUnwindSafe for Error
impl Send for Error
impl Sync for Error
impl Unpin for Error
impl UnsafeUnpin for Error
impl UnwindSafe for Error
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more