#[non_exhaustive]pub enum FetchError {
UnsupportedType(String),
MissingField(&'static str),
Download(String),
Throttled {
url: String,
status: u16,
retry_after: Option<u64>,
},
Unauthorized {
url: String,
status: u16,
},
NotFound {
url: String,
},
UnexpectedStatus {
url: String,
status: u16,
},
Io(Error),
Extract(String),
}Expand description
Errors that can occur during input fetching.
§Why the HTTP failures are separate variants
Every network failure used to collapse into FetchError::Download, a
single String. The status code was known — it was read as a u16 and
immediately formatted into prose — so a rate-limit and a missing repository
arrived at the caller as the same shape, distinguishable only by matching
English text.
That cost real work, measured 2026-08-17: GitHub throttled a flake input’s
archive on one host while the API quota showed 4653/5000 remaining (a
per-egress-IP limit on archive generation, unaffected by holding a valid
token), and two full rebuilds died before the cause was understood. The
remedy for a throttle is unlike the remedy for anything else here — another
egress can fetch the identical bytes, and flake.lock’s pinned narHash
makes “identical” checkable rather than merely hoped-for — so a consumer
has to be able to branch on it. A downstream tool
(pleme-io/fleet’s warm-inputs) was reduced to contains("HTTP error 429") on this crate’s own error text for exactly that reason.
So: no status is discarded, and FetchError::UnexpectedStatus exists so
that adding a new HTTP behaviour cannot silently fall back into a prose
bucket — an unclassified code still arrives as a number.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
UnsupportedType(String)
MissingField(&'static str)
Download(String)
A genuine transport failure — DNS, TLS, connect timeout, body read. Not a status: an HTTP response that arrived and said “no” is one of the four typed variants below.
Throttled
The upstream refused to serve content it has: HTTP 429, or a 403 whose
body names a secondary rate limit. retry_after carries the server’s
own Retry-After in seconds when it sent one — the only authority on
how long to wait, and previously thrown away unread.
401 or 403 — our credential, not the content. Another egress does not help; the token does.
Fields
NotFound
- For a private input this is frequently an auth failure wearing a not-found mask, which is why the message says so rather than asserting the content is absent.
UnexpectedStatus
Any other non-2xx. Carries the code so an unhandled status is still a number a caller can act on, never prose.
Io(Error)
Extract(String)
Implementations§
Source§impl FetchError
impl FetchError
Sourcepub fn status(&self) -> Option<u16>
pub fn status(&self) -> Option<u16>
The HTTP status, when this failure carried one.
Exists so a caller branches on a number rather than re-deriving one from
the Display text — which is the habit this enum was widened to end.
Sourcepub fn is_throttled(&self) -> bool
pub fn is_throttled(&self) -> bool
Whether fetching the identical bytes from a different network egress could succeed.
True only for a throttle. A 401/403/404 is about our credential or
the content, so another host is refused identically — and answering
true there would send an operator to build a second fetch path that
cannot work.
Trait Implementations§
Source§impl Debug for FetchError
impl Debug for FetchError
Source§impl Display for FetchError
impl Display for FetchError
Source§impl Error for FetchError
impl Error for FetchError
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()
Auto Trait Implementations§
impl !RefUnwindSafe for FetchError
impl !UnwindSafe for FetchError
impl Freeze for FetchError
impl Send for FetchError
impl Sync for FetchError
impl Unpin for FetchError
impl UnsafeUnpin for FetchError
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
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
Source§impl<T> ErrorExt for T
impl<T> ErrorExt for T
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> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.