Skip to main content

ContentError

Enum ContentError 

Source
#[non_exhaustive]
pub enum ContentError { EncodingError { source: Box<dyn Error + Send + Sync + 'static>, }, DecodingError { source: Box<dyn Error + Send + Sync + 'static>, }, VerificationFailed { expected: String, computed: String, }, NonCanonical, LossyDecode, InvalidCid { reason: String, source: Box<dyn Error + Send + Sync + 'static>, }, InvalidCidProfile { reason: String, }, }
Expand description

The error type returned by all fallible operations in this crate.

Variants are intentionally coarse: they describe which stage failed (serialize, deserialize, verify, non-canonical, parse) rather than mirroring every underlying library error one-to-one. Where a lower-level error is available it is preserved in the source field for diagnostics.

§Stability (FROZEN at 0.1.0)

This enum is #[non_exhaustive] as a frozen decision: it lets a new variant be added in a future 0.1.x release without a major version bump, while the seven names and their fields below are a stability contract. (Six were frozen at 0.1.0; LossyDecode was added in 0.1.2 through exactly that additive path.) See the module docs for the full freeze rationale (no #[from], boxed codec sources, the operation→variant map) and a compile-time Send + Sync + 'static guard locking ContentError’s thread-portability.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

EncodingError

Canonical dag-cbor encoding of a value failed.

Returned by to_canonical_dagcbor (and so propagated by content_id / verify via canonical_form). The source is boxed as a dyn Error so the concrete serde_ipld_dagcbor::EncodeError<…> generic does not leak into this frozen signature.

Fields

§source: Box<dyn Error + Send + Sync + 'static>

The underlying codec error, type-erased.

§

DecodingError

Decoding dag-cbor bytes back into a value failed.

Returned by every decode path in the crate, checked or not: from_canonical_dagcbor (the deprecated unchecked door), from_canonical_dagcbor_checked, ContentAddressable::from_canonical_form, and from_canonical_bytes_checked.

It covers two distinct situations, and the checked doors reach both: the bytes are not dag-cbor at all, or they are dag-cbor but do not decode as the target type. For a type whose canonical_form is deliberately not its serde representation, the second is the expected answer for its own canonical bytes — see from_canonical_form.

The source is boxed as a dyn Error so the concrete serde_ipld_dagcbor::DecodeError<…> generic does not leak into this frozen signature.

Fields

§source: Box<dyn Error + Send + Sync + 'static>

The underlying codec error, type-erased.

§

VerificationFailed

A crate::ContentId did not match the expected one.

This is the heart of the doctrine: the data did not carry the proof it claimed to. The recomputed identity differs from the expected identity.

§Frozen verify ruling (0.1.0)

verify returns Ok(false) on a mismatch — a mismatch is not an Err (a negative answer to “do these match?” is a successful, expected result, not a failure to check). This is a frozen part of the 0.1.0 API surface (README gate item #8). This variant is the escalation of that boolean: it is constructed by ensure_content_id, the strict helper that turns a mismatch into an Err for ?-propagation. Its expected / computed fields are the two ids’ Display strings (multibase base32-lower b…).

Fields

§expected: String

The identity the caller expected, as a ContentId Display string.

§computed: String

The identity actually computed from the bytes, as a ContentId Display string.

§

NonCanonical

Bytes presented as canonical dag-cbor were valid CBOR but not canonical dag-cbor.

Returned by every door that verifies canonicality, all of which run one shared generic gate: from_canonical_bytes_checked, from_canonical_dagcbor_checked, and ContentAddressable::from_canonical_form — plus the unstable-store seam’s strict ingest and identity-preserving read, which are those doors under other names.

It means the input decoded as an Ipld value but re-encoding it did not reproduce the input bytes (wrong map-key order, indefinite-length items, non-smallest integers, …). No target type is involved: the verdict is about the bytes alone, which is why it is established before any type is constructed. The fast from_canonical_bytes primitive never produces this — it trusts its precondition and only hashes.

§

LossyDecode

A typed round-trip mismatch: the value decoded, but re-encoding it does not reproduce the input bytes.

Produced at the third stage of the two checked doors — canonical::from_canonical_dagcbor_checked, which re-encodes with to_canonical_dagcbor, and ContentAddressable::from_canonical_form, which re-encodes with the type’s own canonical_form. Those two are the only crate-owned stage-three construction sites — a user’s own canonical_form may of course return this public variant, and when it does the crate propagates it verbatim rather than reinterpreting it (see below).

The bytes were already proven canonical by the time this can fire, so they are not at fault: the mismatch is between the input and the target type’s canonical representation of what it decoded.

Information loss is the usual cause and the one that motivated the variant: serde ignores unknown map keys by default, so a record carrying a field the type does not name decodes cleanly with the field gone, and for a protocol record that field may have been a required demand. #[serde(default)] and aliases land in the same place. It is not the only cause, though, and a LossyDecode is not by itself proof that a field was dropped: a type whose canonical_form intentionally differs from its serde representation can decode faithfully and still re-encode to different bytes. Either way the conclusion the caller needs is the same — these bytes are not the canonical form of this value — which is why one variant covers both, and why the display message speaks of the mismatch rather than naming a missing field.

Distinct from NonCanonical on purpose: NonCanonical blames the bytes (re-encode them), LossyDecode blames the bytes/type pairing (widen the type, name every field, or give the custom canonical form the custom decoder it needs). Like NonCanonical it is a policy rejection and carries no underlying source — nothing failed underneath; the comparison simply came out unequal.

Two things it is not. It is not what a user’s own canonical_form returning an error produces — that error propagates verbatim, whatever it is. And under the unstable-store seam it is not what a mismatched typed read reports: NodeStoreExt::get_node returns its own StoreError::RepresentationMismatch, which names the id that lied, so a LossyDecode surfacing from that seam came from the user’s encoder.

Added in 0.1.2 (issue #90) under the enum’s #[non_exhaustive] contract.

§

InvalidCid

A CID could not be parsed from a string or from bytes.

Returned by ContentId::from_bytes and the FromStr impl. reason is a stable human-readable string; the underlying cid::Error is preserved in source so the error chain (.source()) is not stripped at this boundary.

Fields

§reason: String

Human-readable description of why the CID is invalid.

§source: Box<dyn Error + Send + Sync + 'static>

The underlying CID parse error, preserved for .source() chaining.

§

InvalidCidProfile

A syntactically-valid CID was parsed, but it is not this crate’s frozen profile: CIDv1 + dag-cbor (0x71) + BLAKE3 (0x1e) + a 32-byte digest.

Every ingress path — from_bytes, the FromStr impl, TryFrom<Cid>, and the binary/IPLD Deserialize — rejects a foreign CID with this, so every ContentId (however it entered) carries the fixed profile the presentation accessors (digest_bytes etc.) rely on. A policy rejection, so — like NonCanonical — it carries no underlying source; reason names the parameter that was off.

Fields

§reason: String

Which profile parameter was wrong (version / codec / hash / digest length).

Trait Implementations§

Source§

impl Debug for ContentError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ContentError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ContentError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.