pub enum DownloadError {
Transport {
provider: String,
reason: String,
},
Timeout {
provider: String,
},
Verify(VerifyError),
NoProviders {
needed: usize,
},
NotFound {
content: String,
},
MetadataProbeFailed {
content: String,
holders: usize,
reasons: Vec<String>,
},
PagedPrologueUnsupported {
provider: String,
chunk_count: u64,
delivered: u64,
},
Cancelled,
State(String),
Sink(String),
NotDownloadable,
TaskEnded,
}Expand description
An error from a download operation.
Variants§
Transport
A transport-level failure fetching from one provider (connect failed, stream dropped, availability/range RPC errored, timeout). Carries the reason as text. Recoverable: the orchestrator marks the provider suspect and re-queues the range to another holder.
Fields
Timeout
A range fetch exceeded the configured per-range timeout (DownloadConfig::range_timeout) — a
too-slow or stalled source. Recoverable: the range is re-queued to another holder and the
slow source is backed off (its TimedOut outcome is reported to the selector).
Verify(VerifyError)
A fetched range failed integrity verification. Recoverable: the bad range is discarded and re-fetched from a different provider, and the serving provider is penalized.
The wrapped reason is SANITIZED here for the same reason a transport reason is: a verify failure
routinely quotes peer-reported metadata (a first-frame root, a declared length), so it is
untrusted text arriving through a different door.
NoProviders
A still-needed range has no live provider left to fetch it from — every known holder has been
tried + failed and a fresh find_providers discovered no more. This is terminal for the
download (there is nowhere left to get the missing bytes).
NotFound
The content could not be fetched at all — either find_providers returned no holders, or
no located holder could answer the metadata probe. Terminal.
content names the content id AND which of those two steps failed: the message must never
blame discovery for a probe failure (that ambiguity cost four #1586 investigations).
MetadataProbeFailed
Holders WERE located and confirmed, but not one of them could seed the resource layout. Terminal.
This is the named replacement for reporting that outcome as a generic
NotFound. The two failures are not the same event and must not read the
same: “nobody has this content” is a discovery result, while “several holders have it and every
one of them served metadata this reader cannot use” is a compatibility or hostility result, and
only the second is actionable by whoever operates the holders. Collapsing them cost four separate
#1586 investigations.
reasons carries the per-holder cause, which was previously written to a tracing::debug! and
then dropped — so the one fact that identifies the fault survived only if debug logging happened
to be on.
Fields
PagedPrologueUnsupported
The resource’s chunk_lens paged prologue could not be COMPLETED — the stream ended short of
the declared chunk_count, or a first frame that declared no multi-page layout was followed by a
frame paging one. Recoverable per holder: the range is retried elsewhere and the adoption path
probes the next holder.
§Fail-closed, not a reader limitation
This reader DOES reassemble a paged prologue (SPEC.md §2.2), so a conforming multi-page holder
reads end-to-end. The error is raised only when the layout stays INCOMPLETE — a decrypt-input array
short of chunk_count would decrypt every chunk to garbage, so it is refused rather than adopted
partial. It reports the declared count and the entries delivered so a short prologue is
distinguishable from “nobody holds this content”. (A page that violates a placement rule —
misaligned, duplicated, overshooting — surfaces instead as a recoverable Transport
naming the broken rule.)
Fields
Cancelled
The download was cancelled via DownloadHandle::cancel.
Terminal (by request).
State(String)
Persisting or loading resume state failed. Carries the reason.
Sink(String)
The sink (store-write path) rejected a write. Carries the reason.
NotDownloadable
The requested content id cannot be downloaded as a byte stream — a bare store id names a whole store (many capsules), not a single resource/capsule to fetch. Supply a root/capsule or resource content id.
TaskEnded
The orchestrator task ended unexpectedly (its channel closed before a terminal result). This indicates a bug or an aborted runtime, not a normal download outcome.
Implementations§
Source§impl DownloadError
impl DownloadError
Sourcepub fn transport(provider: impl Into<String>, reason: impl Display) -> Self
pub fn transport(provider: impl Into<String>, reason: impl Display) -> Self
Build a DownloadError::Transport for provider from anything displayable.
Sourcepub fn sink(reason: impl Display) -> Self
pub fn sink(reason: impl Display) -> Self
Build a DownloadError::Sink from anything displayable.
Sourcepub fn state(reason: impl Display) -> Self
pub fn state(reason: impl Display) -> Self
Build a DownloadError::State from anything displayable.
Sourcepub fn is_recoverable(&self) -> bool
pub fn is_recoverable(&self) -> bool
Whether this error is recoverable per range (the download can continue by retrying the range elsewhere) rather than terminal for the whole download.
PagedPrologueUnsupported is recoverable for the same reason a
transport failure is: it rules out ONE holder’s stream, not the content. The other new variants
are terminal — each already reports that every holder was tried.
Sourcepub fn attributed_to(self, peer_id: &str) -> Self
pub fn attributed_to(self, peer_id: &str) -> Self
Fill in an as-yet-unattributed provider with the peer the failure came from, leaving every other
variant untouched.
The pure reassembly core cannot know which peer it is reading, so it raises errors with an empty
provider for the transport layer to stamp. Stamping must not be done by WRAPPING, which is what
this replaced: re-wrapping every reassembly failure into a Transport flattened
the typed ones, so a variant the reassembler raised deliberately — and that
is_recoverable treats specially — could never be observed by a caller.
An already-attributed error is returned unchanged, so stamping twice cannot relabel a failure onto the wrong peer.
Trait Implementations§
Source§impl Debug for DownloadError
Debug delegates to the SANITIZING Display rather than printing raw fields.
impl Debug for DownloadError
Debug delegates to the SANITIZING Display rather than printing raw fields.
Debug is not a developer-only rendering in practice: tracing’s ?field, a {:?} in a log line,
and every unwrap/expect panic message emit it. A derived Debug would print the untrusted
provider / reason / verify text verbatim — unbounded, with markup intact — bypassing the very
sanitization Display applies. One rendering, one door.
Source§impl Display for DownloadError
impl Display for DownloadError
Source§impl Error for DownloadError
impl Error for DownloadError
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()
Source§impl From<HopPathError> for DownloadError
impl From<HopPathError> for DownloadError
Source§fn from(e: HopPathError) -> Self
fn from(e: HopPathError) -> Self
Source§impl From<VerifyError> for DownloadError
impl From<VerifyError> for DownloadError
Source§fn from(source: VerifyError) -> Self
fn from(source: VerifyError) -> Self
Auto Trait Implementations§
impl Freeze for DownloadError
impl RefUnwindSafe for DownloadError
impl Send for DownloadError
impl Sync for DownloadError
impl Unpin for DownloadError
impl UnsafeUnpin for DownloadError
impl UnwindSafe for DownloadError
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
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> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.