Typed errors
Every error the urna Rust crates return: the 38 UrnaError variants, the 10 RuntimeError variants, and the public functions that panic on misuse.
The Rust crates report every failure as a typed error. urna-format returns UrnaError, and urna-runtime returns RuntimeError, which wraps UrnaError for anything found in the file itself. This page lists every variant, its message, and when it happens. A malformed file never panics: the few panics below come from calling a public function with inconsistent arguments.
UrnaError
urna_format::UrnaError, 38 variants. urna_format::Result<T> is std::result::Result<T, UrnaError>. Section ids in messages are printed in decimal (section 0x15 appears as 21).
File structure
| Variant | Message | When it happens |
|---|---|---|
FileTruncated | file truncated | the file is shorter than 168 bytes, or the section table or manifest runs past the footer |
MagicMismatch { expected, got } | magic mismatch: expected .., got .. | the first 4 bytes are neither URNA nor NEST (a file that is not .urna) |
UnsupportedVersion(major, minor) | unsupported version: {major}.{minor} | header major is not 1, or minor is above 0 |
InvalidHeaderChecksum | invalid header checksum | the header bytes do not match their checksum |
FileSizeMismatch { expected, got } | file size mismatch: expected .., got .. | header file_size differs from the file length (a truncated or appended file) |
SectionOffsetOutOfBounds { section_id, offset } | section {id} offset out of bounds: {offset} | a section, or the table itself (reported as section 0), overflows or runs past the footer |
SectionMisaligned { section_id, offset, alignment } | section {id} offset not aligned: .. | a section offset is not a multiple of 64 |
SectionChecksumMismatch(id) | section {id} checksum mismatch | a section's bytes do not match its checksum |
FooterHashMismatch | footer hash mismatch | the bytes before the footer do not match the footer hash |
MissingRequiredSection(name) | missing required section: {name} | one of the six required sections is absent |
SectionNotFound(id) | section {id} not found | UrnaView::entry asked for an id the file lacks |
UnexpectedEof | unexpected end of file | a low-level byte reader in urna_format::bytes, or UrnaFooter::from_bytes, got too few bytes |
Encodings and payloads
| Variant | Message | When it happens |
|---|---|---|
UnsupportedSectionEncoding { section_id, encoding } | unsupported section encoding: section=.. encoding=.. | the encoding is not legal for that section (zstd on embeddings, a reserved or unknown id, zstd_dict decoded without its dictionary) |
UnsupportedSectionVersion { section_id, version } | unsupported section payload version: .. | a payload declares a version its decoder does not know |
MalformedSectionPayload { section_id, reason } | malformed section payload: section=.. reason=.. | a payload fails to decode: truncation, a count larger than the bytes can hold, a zstd frame over the decompression cap, an unknown kind byte, a blob overlay pointing past blob_refs, a non-raw blob_data, a node count that does not match |
SectionCountMismatch { section_id, expected, got } | section count mismatch: .. | chunk_ids, chunks_canonical or spans hold a different number of entries than the header says |
EmbeddingSizeMismatch { expected, got } | embedding size mismatch: .. | the embeddings section or a band has the wrong size for its count, dimension and dtype |
UnsupportedDType(String) | unsupported dtype: {0} | an unknown dtype, or a count times dimension that overflows |
Manifest
| Variant | Message | When it happens |
|---|---|---|
Json(serde_json::Error) | JSON error: {0} | the manifest, provenance or search contract is not valid JSON, or lacks a required key |
UnsupportedFormatVersion(u32) | unsupported format_version: {0} | manifest format_version above 1 |
UnsupportedSchemaVersion(u32) | unsupported schema_version: {0} | manifest schema_version above 1 |
ManifestInvalid(String) | manifest invalid: {0} | a manifest rule fails (empty model or chunker, zero dimension or chunks, hnsw without rerank_policy = "exact", Matryoshka fields inconsistent), the manifest disagrees with the header, the embeddings encoding does not match dtype, a listed space band is missing, or the builder got a chunk count different from n_chunks |
InvalidModelHash(String) | invalid model_hash: {0} | model_hash is not sha256: plus 64 hex digits |
UnsupportedMetric(String) | unsupported metric: {0} | metric is not ip, or search_contract disagrees with the manifest |
UnsupportedScoreType(String) | unsupported score_type: {0} | score_type is not cosine or hybrid_rrf, or the contract disagrees |
UnsupportedNormalize(String) | unsupported normalize: {0} | normalize is not l2, or the contract disagrees |
UnsupportedIndexType(String) | unsupported index_type: {0} | index_type is not exact, hnsw or hybrid, or the contract disagrees |
UnsupportedRerankPolicy(String) | unsupported rerank_policy: {0} | rerank_policy is not none or exact, or the contract disagrees |
When the cause is a search_contract disagreement, the message reads section says X but manifest says Y.
Writing
| Variant | Message | When it happens |
|---|---|---|
DimensionMismatch { expected, got } | dimension mismatch: .. | a ChunkInput embedding has the wrong length |
InvalidEmbeddingValue | NaN or Inf detected in embeddings | a chunk vector, a stored slab or a scale holds NaN or Inf (on write, and in validate_embeddings_values) |
InvalidInput(String) | invalid input: {0} | byte_end below byte_start, a string over 4 GiB, a zstd or dictionary failure, an int8 or int4 encoder given the wrong number of values, oversized JSON |
Io(std::io::Error) | I/O error: {0} | write_to_path cannot write the file |
Declared but never returned
These variants exist in 0.5.1 but no code path constructs them. Query errors come from RuntimeError instead.
| Variant | Message |
|---|---|
QueryValidation(String) | query validation failed: {0} |
InvalidK(i32) | invalid k parameter: {0} |
EmptyQuery | empty query |
ZeroNormQuery | zero-norm query |
FileNotFound(String) | file not found: {0} |
UnsupportedFeature(String) | unsupported feature: {0} |
RuntimeError
urna_runtime::RuntimeError, 10 variants.
| Variant | Message | When it happens |
|---|---|---|
Format(UrnaError) | the inner message | any format-level failure at open or during a search |
Io(std::io::Error) | the OS message | open cannot open or map the file, for example No such file or directory (os error 2) |
DimensionMismatch { expected, got } | dimension mismatch: expected .., got .. | the query length differs from embedding_dim (or the space dimension) |
InvalidK(i32) | invalid k: {0} | k is 0 or negative |
EmptyQuery | empty query | the query slice is empty |
ZeroNormQuery | zero-norm query | the query vector has norm 0 |
InvalidQueryValue | NaN or Inf in query | a query component is not finite |
SpaceNotFound(String) | embedding space not found: {0} | search_space with a name the file does not have |
BlobNotInlined { index } | blob {index} is not inlined in this file: .. | blob_bytes on a file without 0x17, an index out of range, or a record kept outside the file |
SpaceModelMismatch { space, expected, actual } | model_hash mismatch in space .. | search_space with an expected_model_hash that differs from the space's |
Query checks run in the order InvalidK, EmptyQuery, DimensionMismatch, InvalidQueryValue, ZeroNormQuery. search_space checks SpaceNotFound, then SpaceModelMismatch when you pass a hash, before those five.
Match on the wrapped variant to handle file problems apart from query problems:
use std::path::Path;
use urna_format::UrnaError;
use urna_runtime::{MmapUrnaFile, RuntimeError};
let path = Path::new("corpus.urna");
match MmapUrnaFile::open(path) {
Ok(file) => { /* search */ }
Err(RuntimeError::Io(e)) => eprintln!("cannot read {}: {e}", path.display()),
Err(RuntimeError::Format(UrnaError::MagicMismatch { .. })) => eprintln!("not a .urna file"),
Err(e) => eprintln!("corrupt or unsupported file: {e}"),
}Panics on misuse
These public functions panic when called with inconsistent arguments. None of them is reachable from a malformed file through UrnaView::from_bytes or MmapUrnaFile::open.
| Function | Panics when |
|---|---|
UrnaFooter::from_bytes | given more than 40 bytes (fewer returns UnexpectedEof) |
HnswIndex::build | vectors.len() is not n * dim |
simd::dot_f32_bytes, dot_f32_f16_bytes, dot_f32_i8, dot_f32_i4_blocked, score_int8_section | the slice lengths do not match; the checks stay on in release builds on purpose |
Int4EmbeddingsView::row_scales_into | out.len() is not the number of blocks per row |
Int8EmbeddingsView::row, scale; Int4EmbeddingsView::group_scale, row_codes | the row or block index is out of range |
quantize_f32_to_i4(values, dim) | values is shorter than dim |
UrnaView::get_section_data | the public section_table field was modified after parsing to point outside the file |
Python
The Python bindings turn every Rust error into ValueError with the same message, for example dimension mismatch: expected 4, got 2. Argument conversion raises TypeError or OverflowError. The full list is on Python errors.
The CLI prints these messages on stderr and maps failures to exit codes: see Exit codes.
Exit codes
Exit codes of every urna command: the typed codes of doctor, setup and build, the engine and agent verbs, the explorer, the installers and the wheel's command.
Query embedder protocol
How the urna CLI finds, runs and checks the Python scripts that embed a text query: arguments, the JSON on stdout, exit status and lookups.