#[non_exhaustive]pub enum Error {
Show 43 variants
Io(Error),
Corruption {
page_id: u64,
},
WalCorruption {
frame_offset: u64,
},
InvalidFormat {
reason: &'static str,
},
InvalidArgument(&'static str),
BTreeDepthExceeded {
limit: usize,
},
BTreeKeyTooLarge {
key_len: usize,
max: usize,
},
BTreeValueTooLarge {
value_len: usize,
max: usize,
},
BTreeKeyExists,
BTreeScanLimitExceeded {
limit: usize,
},
BTreeInvariantViolated {
reason: &'static str,
},
DocumentTooLarge {
len: usize,
max: usize,
},
CollectionIdMismatch {
expected: u32,
found: u32,
},
SchemaMigrationNotImplemented {
collection: &'static str,
from_version: u32,
to_version: u32,
},
SchemaVersionFromFuture {
collection: &'static str,
from: u32,
to: u32,
},
CollectionAlreadyExists {
name: String,
},
IdSpaceExhausted {
collection: String,
},
Codec(Error),
Busy {
kind: LockKind,
},
ReadOnly {
operation: &'static str,
},
CollectionNotFound {
name: String,
},
DocumentNotFound {
collection: &'static str,
id: u64,
},
IndexFieldMissing {
collection: String,
index: String,
path: String,
},
IndexNotFound {
collection: String,
name: String,
},
IndexNotUnique {
collection: String,
name: String,
},
IndexKindMismatch {
name: String,
expected: IndexKind,
found: IndexKind,
},
IndexKeyPathsMismatch {
name: String,
},
UniqueConstraintViolation {
collection: String,
index: String,
key: Vec<u8>,
},
EachIndexTooLarge {
collection: String,
index: String,
len: usize,
max: usize,
},
IndexFieldTypeMismatch {
collection: String,
index: String,
path: String,
expected: &'static str,
found: &'static str,
},
SortBufferExceeded {
limit: usize,
},
SortKeyEncode {
source: Box<Error>,
},
DistinctCountExceeded {
limit: usize,
},
SchemaNotRegistered {
collection: &'static str,
version: u32,
},
SchemaDepthExceeded {
depth: usize,
},
SchemaTypeMismatch {
expected: &'static str,
found: &'static str,
path: String,
},
DynamicPathNotMap {
path: String,
},
BackupDestinationExists {
path: PathBuf,
},
BackupNotSupportedForMemoryPager,
AttachmentAlreadyExists {
namespace: String,
},
AttachmentNotReadable {
path: PathBuf,
source: Box<Error>,
},
AttachedDatabaseIsReadOnly {
namespace: String,
collection: String,
},
CollectionNamespaceUnknown {
namespace: String,
},
}Expand description
The pager-level error type.
Construct variants directly when synthesising an error; downstream
callers should match exhaustively or use the #[non_exhaustive]
catch-all so that future variants are not source-breaking additions.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Io(Error)
An I/O error from the platform layer (file open, read, write,
flush). Wraps the underlying std::io::Error for inspection
and never silently discards it (Rule 7).
Corruption
The on-disk image is malformed or its checksum does not match.
page_id is the page where corruption was detected; the value
0 refers to the file header. The error carries no source —
corruption is the direct failure mode.
WalCorruption
A WAL frame whose CRC32C does not validate sits before the
last commit marker in the current generation. Unlike a torn
tail (silently discarded), mid-WAL corruption is a recovery
error: replaying past it would drop or alias durable data, and
recovery refuses to guess. frame_offset is the byte offset
of the bad frame in the WAL file. See docs/format.md
§ Recovery semantics.
InvalidFormat
The file’s magic, page-size, or major version is not what this
build of the library understands. Distinct from Corruption
because the file may be perfectly valid for a different reader.
Fields
InvalidArgument(&'static str)
Caller passed an out-of-range PageId, capacity, or similar
numeric input that the type system could not statically
rule out. Always indicates a caller bug.
BTreeDepthExceeded
A B+tree traversal exceeded its statically-bounded depth limit
(MAX_BTREE_DEPTH = 32). Power-of-ten Rule 1: every recursive
shape is bounded; this is the surfaced error when the bound
trips, not a panic.
BTreeKeyTooLarge
A B+tree insert was given a key longer than the format spec
permits (PAGE_SIZE / 4). See docs/format.md § Key and
value encoding.
Fields
BTreeValueTooLarge
A B+tree insert was given a value too large to fit inline in a leaf alongside at least one slot. Overflow chains are deferred to a future minor format version.
Fields
BTreeKeyExists
A B+tree insert was given a key that already exists in the tree. M4 trees do not allow duplicates; the multi-value / composite-key story arrives in M7.
BTreeScanLimitExceeded
A B+tree range scan exceeded the per-scan node budget
(MAX_RANGE_NODES = 1_000_000). Power-of-ten Rule 2.
BTreeInvariantViolated
A B+tree invariant that debug_assert! would normally catch
has tripped in a release build. Surfaced as an Error rather
than a panic per power-of-ten Rules 5 + 7.
DocumentTooLarge
A document encode call produced a record larger than the
B+tree leaf can hold inline. Overflow chains for oversize
documents are deferred to a later format-minor (see
docs/format.md § Document records). M5 documents must fit
inline.
Fields
CollectionIdMismatch
A decode call observed a per-document header whose
collection_id does not match the catalog row for the
Document type being decoded. Indicates a programming bug
(wrong type at a key) or a forensic mishap (cross-collection
byte forgery) — never a transient I/O issue.
Fields
SchemaMigrationNotImplemented
The on-disk record’s type_version is older than the
Document::VERSION of the Rust type, and that type’s
Migrate impl is the default-erroring body. Real
Document types override Migrate::migrate to handle this.
Fields
SchemaVersionFromFuture
The on-disk record’s type_version is newer than the
reader’s Document::VERSION. The reader refuses to guess
what the unknown fields mean — better a hard error than a
silent loss of data.
Fields
CollectionAlreadyExists
Catalog::insert was called for a name already present in the
catalog. The user should call Catalog::update instead, or
pick a different name.
IdSpaceExhausted
Per-collection Id allocator exhausted its u64 space, or
the catalog’s per-collection-id u32 space. At 10⁹/sec the
u64 case takes ~584 years; this is a defense-in-depth
check (Rule 5) not a likely runtime event.
The collection field is an owned String so user-supplied
&str names can be reported verbatim without leaking a
'static slot. The #[non_exhaustive] attribute on Error
keeps this widening backward-compatible for downstream
pattern-matchers.
Codec(Error)
A postcard encode or decode operation failed at the codec
boundary. The wrapped error carries postcard’s diagnostic;
obj does not further interpret it because postcard is treated
as a black-box codec (docs/format.md § Postcard pin).
Busy
A cross-process or in-process lock was contended for the
caller-supplied timeout (Config::busy_timeout or the
explicit deadline passed to FileHandle::lock_writer /
FileHandle::lock_reader). Power-of-ten Rule 2: every wait
has an explicit budget; exhausting it surfaces here rather
than blocking the caller forever. See docs/format.md
§ File locking for the lock-byte layout and the protocol.
ReadOnly
The Db was opened with Db::open_readonly and the caller
invoked an operation that would mutate the database.
Surfaced eagerly so callers never have to inspect the
underlying lock state to know the call was illegal.
Fields
CollectionNotFound
A typed-API caller asked for a collection that the catalog
does not have a row for. Distinct from
Error::CollectionAlreadyExists (the insert-side dual);
distinct from Error::Corruption (which would indicate a
catalog row is malformed, not absent).
DocumentNotFound
A Collection::update or Collection::delete was given an
id that does not exist in the collection’s primary B-tree.
IndexFieldMissing
An index extraction call (#56) was unable to resolve the
configured field path against the document’s Dynamic view.
The document does not carry a value at the path the index
names — typically a schema-evolution gap: the type used to
have the field, an older document did not, and reconciliation
has not rewritten it yet.
Fields
IndexNotFound
Lookup of a named index against a collection’s descriptor
failed: the catalog has no IndexDescriptor with that name,
or the descriptor exists but is in DroppedPending status.
Fields
IndexNotUnique
Collection::find_unique was called on an index that is not
Unique — find_unique is only defined for unique indexes.
Callers that want non-unique lookups should use
Collection::lookup.
Fields
IndexKindMismatch
The reconciler observed a runtime crate::index::IndexSpec whose
kind disagrees with the on-disk descriptor of the same
name. To change an index’s kind the application must
drop-then-redeclare under a different name (or rebuild from
scratch); silent in-place rewrites would invalidate any
extant entries.
Fields
IndexKeyPathsMismatch
The reconciler observed a runtime crate::index::IndexSpec whose
key_paths disagree with the on-disk descriptor of the
same name and kind. Like Error::IndexKindMismatch, the
only safe response is for the application to drop-and-
redeclare under a different name.
UniqueConstraintViolation
A Unique index extraction observed a key value that
already exists on a different document in the same
collection. The maintenance path surfaces this rather than
silently overwriting; the WAL transaction rolls back so no
partial state remains.
Fields
EachIndexTooLarge
A single document’s Each extraction emitted more than the
per-doc ceiling number of index entries — almost certainly
the application supplied a runaway sequence rather than a
real indexable field.
Fields
IndexFieldTypeMismatch
An index extraction call (#56) resolved a field path but the
value’s Dynamic shape disagrees with the index kind’s
contract — e.g. an Each index whose target field is not a
sequence, or a Composite field that resolved to a Map
(only primitive Dynamic values are indexable).
Fields
SortBufferExceeded
An M8 query’s sort_by extension collected more than its
sort_buffer_limit (default 100 000) candidate documents
before the sort+truncate step could narrow them down.
Power-of-ten Rule 3: the in-memory sort is bounded; the user
should add a .filter / .index_range / .limit that bounds
the survivors, or raise the limit explicitly via
.sort_buffer_limit(N) if the workload genuinely needs it.
M8 sorts are designed for “screen-of-results” workloads, not “sort a million rows” workloads; a disk-spill sort is the post-M8 follow-up if this turns out to be too restrictive.
SortKeyEncode
An M8 query’s sort_by extractor produced a Dynamic whose
obj_core::index::encode_field representation could not be
computed (e.g. a Dynamic::String carrying an embedded NUL
byte, which the order-preserving encoder rejects). Power-of-
ten Rule 7: the underlying error is propagated rather than
silently collapsed into an empty key. Callers who want to
control the encoding themselves should use
Query::sort_by_bytes, which never touches encode_field.
Fields
DistinctCountExceeded
Collection::count_distinct_ids_in_range (M8 follow-up #72)
observed more than the caller-configurable per-call cap of
distinct Ids while walking the index B-tree. Power-of-ten
Rule 3: the in-memory HashSet<Id> is bounded; the user
should narrow the range via .index_range(...) so fewer
distinct docs fall inside the window. The fast path on the
query layer dispatches to this routine ONLY for Each-kind
indexes — other kinds count entries via the cheaper
count_index_range path that has no distinct-tracking cost.
SchemaNotRegistered
codec::decode saw an on-disk record whose type_version is
older than the reader’s Document::VERSION, but the reader’s
Document::historical_schemas() has no entry for that version
(M10 issue #82 introduces the registry; M10 issue #83 wires
this error). The codec refuses to invent a Dynamic view —
silent fallback hides schema-evolution bugs.
Fields
SchemaDepthExceeded
The postcard byte-stream walker driven by
Dynamic::from_postcard_bytes
exceeded the depth bound
MAX_SCHEMA_DEPTH.
Power-of-ten Rule 1: the walker uses an explicit stack, but
the stack depth is itself bounded to avoid a pathological
schema triggering unbounded growth.
SchemaTypeMismatch
The postcard byte-stream walker observed a payload that
disagrees with the supplied schema in a way the schema
itself cannot recover from (e.g. a Bool slot carrying a
byte other than 0 / 1, a String slot whose bytes are
not UTF-8, or a Seq length that overflows the input). M10
issue #41.
Fields
DynamicPathNotMap
Dynamic::remove (M10 issue #85) was called on a Dynamic
whose root value (or any intermediate path segment) is not a
Map. Map-only by construction —
callers needing scalar removal should replace the value
outright via Dynamic::set.
BackupDestinationExists
Db::backup_to (M11 #92) was called with a destination path
that already exists. The backup never overwrites existing
files — the operator must remove the destination explicitly
or pick a fresh path.
BackupNotSupportedForMemoryPager
Db::backup_to (M11 #92) was called on an in-memory database.
Memory pagers have no file backend; serialising the in-memory
state to a fresh .obj file is deferred to a future minor.
AttachmentAlreadyExists
Db::attach (M11 #93) was called with a namespace already
registered on the calling Db. Detach the existing
attachment first or pick a different namespace.
AttachmentNotReadable
Db::attach (M11 #93) was unable to open the attached file.
The wrapped error carries the underlying cause (typically
Error::Io or Error::Corruption).
Fields
AttachedDatabaseIsReadOnly
Db::insert / Db::update / Db::delete / Db::upsert (and
the WriteTxn::collection<T>() equivalents) refused to
mutate a collection whose name resolves to an attached
database. Attached databases are read-only through the
calling Db (M11 #93).
Fields
CollectionNamespaceUnknown
A namespaced collection name was opened against a calling
Db that has no attachment registered under the namespace.
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()