Something went wrong. Try again.
STreaming ARchive format: simpler, stricter, smaller than CARs for a subset of use-cases.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137//! Error types for STAR-lite.//!//! The top-level [`enum@Error`] groups failures by phase. Each phase has its//! own detailed enum so callers can match precisely on what went wrong without//! parsing strings.
use std::io;
use star_repo::Cid;use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
/// Top-level error for all crate operations.#[derive(Debug, Error)]pub enum Error { #[error("io: {0}")] Io(#[from] io::Error),
#[error("star-lite framing: {0}")] Format(#[from] FormatError),
#[error("repo: {0}")] Repo(#[from] star_repo::Error),
#[error("storage: {0}")] Storage(#[from] StorageError),
#[error("verify: {0}")] Verify(#[from] VerifyError),}
// `?` shortcuts so call sites can return star-repo error subtypes directly// instead of double-wrapping through `star_repo::Error`.
impl From<star_repo::error::MstError> for Error { fn from(e: star_repo::error::MstError) -> Self { Error::Repo(e.into()) }}
impl From<star_repo::error::CommitError> for Error { fn from(e: star_repo::error::CommitError) -> Self { Error::Repo(e.into()) }}
/// Errors specific to the on-disk STAR-lite framing.#[derive(Debug, Error)]pub enum FormatError { #[error("not a STAR-lite file: bad or missing magic bytes")] InvalidMagic,
#[error( "invalid header CID: must start with 0x01711220 (CIDv1, dag-cbor, sha-256) and be 36 bytes" )] InvalidHeaderCid,
#[error("unexpected end of file")] UnexpectedEof,
#[error("invalid utf-8 in key")] InvalidUtf8(#[from] std::str::Utf8Error),
#[error("keys out of order: {prev:?} must sort strictly before {curr:?}")] KeyOrder { prev: String, curr: String },
#[error("declared size {actual} exceeds limit {limit} for field {field}")] SizeLimit { field: &'static str, actual: u64, limit: u64, },
#[error("writer used incorrectly: {0}")] BadWriterState(&'static str),
#[error("empty key is not allowed")] EmptyKey,
#[error("unknown archive kind byte {0:#04x}; expected 'C' (0x43) or 'L' (0x4c)")] UnknownKind(u8),
#[error( "archive kind mismatch: this operation needs kind {expected:?} but the archive is kind {actual:?}", expected = *expected as char, actual = *actual as char )] KindMismatch { expected: u8, actual: u8 },
#[error("kind {kind:?} cannot be encoded in a v0 header, which has no kind byte", kind = *kind as char)] KindNotRepresentable { kind: u8 },}
/// Errors from the spilling byte storage.#[derive(Debug, Error)]pub enum StorageError { #[error("storage io: {0}")] Io(#[from] io::Error),
#[error("range [{offset}, {offset}+{length}) exceeds storage size {total}")] OutOfRange { offset: u64, length: u64, total: u64, },}
/// Errors from archive verification.#[derive(Debug, Error)]pub enum VerifyError { #[error("{0}")] RootMismatch(Box<RootMismatch>),
#[error("{0}")] CommitmentMismatch(Box<CommitmentMismatch>),}
/// Payload for [`VerifyError::CommitmentMismatch`]: the LtHash computed over a/// kind `L` archive's contents did not match its header commitment.#[derive(Debug, Error)]#[error("computed lthash commitment {computed} does not match the header commitment {declared}")]pub struct CommitmentMismatch { pub declared: String, pub computed: String,}
/// Payload for [`VerifyError::RootMismatch`]. Boxed inside `VerifyError` so/// the `Result` discriminant doesn't carry two CIDs of dead weight on the/// success path.#[derive(Debug, Error)]#[error("computed mst root {computed} does not match commit.data {declared}")]pub struct RootMismatch { pub declared: Cid, pub computed: Cid,}