#[non_exhaustive]pub enum FetchError {
Show 13 variants
NotEligible {
source_key: String,
},
NoOaAvailable,
NotFound {
hint: String,
},
Ambiguous {
hint: String,
},
Http(HttpError),
Log(LogError),
InvalidRef(RefParseError),
NotRetrievable {
source_key: String,
detail: String,
},
SourceSchema {
hint: String,
},
TooManyRefs {
got: usize,
max: usize,
},
TextUnavailable {
arxiv_id: ArxivId,
},
SourceUnavailable {
arxiv_id: ArxivId,
kind: &'static str,
},
Replayed {
code: ErrorCode,
message: String,
retry_after_secs: Option<u64>,
},
}Expand description
Errors returned by Source::fetch.
At the public CLI / MCP boundary, every variant collapses to an
crate::ErrorCode via the From<FetchError> impl below — mirroring
the RefParseError → crate::ErrorCode::InvalidRef collapse from
PR #55.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
NotEligible
The source does not handle the given ref under the runtime
capability profile (covers both can_serve = false outcomes and
runtime denials raised inside fetch).
NoOaAvailable
Tier 1 sources reported no OA URL for this ref.
NotFound
A metadata source authoritatively reported that the identifier does
not exist — distinct from a transport failure. Surfaces as
crate::ErrorCode::NotFound. Used for sources whose
“absent” signal is NOT an HTTP 404/410 (e.g. the arXiv Atom API
returns HTTP 200 with an empty <feed> for an unknown id).
Ambiguous
A name filter (author / venue / publisher) matched MORE than one
OpenAlex entity with no clear winner. Carries a candidate listing
so the caller can narrow the name (or pass an explicit id).
Collapses to crate::ErrorCode::Ambiguous (wire "AMBIGUOUS") —
distinct from NotFound so an agent narrows rather than gives up.
Used by crate::discovery.
Http(HttpError)
Underlying HTTP / network failure. See HttpError.
Log(LogError)
Provenance log write failed. Per docs/SECURITY.md §1.8 this is a
fail-closed signal; the surrounding fetch MUST be aborted.
InvalidRef(RefParseError)
Ref re-parse / validation failed inside the source (e.g. when a source receives a borrowed string from upstream and re-validates).
NotRetrievable
A source found the record and cannot supply a copy — an access refusal, not a failure.
The distinction is the whole point: “the source has it and cannot give it to us” and “the source broke” lead an operator to different conclusions, and only the second is a bug to chase.
This exists as a variant because it used to be a substring search.
A refusal was Self::SourceSchema with an explanatory hint, and
orchestrator::is_access_refusal read the hint back looking for
“not open access” / “openAccess” / “no retrievable PDF”. #503
reworded Europe PMC’s refusal for good reasons, the hint fell out of
that list, and every Europe PMC refusal silently became
AttemptOutcome::Failed. Nothing in the source said the wording was
load-bearing, and hal matched on openAccess — a JSON field
name, not prose anyone chose (#538).
Collapses to crate::ErrorCode::NoOaAvailable, which is an
EXISTING wire code: “found it, no free copy” is exactly what that
means, so the closed set in docs/ERRORS.md §3 does not widen. See
ADR-0054.
Fields
SourceSchema
Source-side schema mismatch (unexpected JSON shape, missing
required field). Surfaces to crate::ErrorCode::InternalError
at the public boundary.
TooManyRefs
Batch orchestrator received more refs than
crate::MAX_BATCH_REFS. Surfaced to the MCP doiget_batch_fetch
tool as ErrorCode::InvalidRef (closest closed-set fit — the
request shape itself is invalid; no denial_context channel
applies). Slice 2 / docs/MCP_TOOLS.md §1.
Fields
max: usizeThe hard cap (crate::MAX_BATCH_REFS).
A source returned a successful response that contained no usable
representation of the requested kind — currently doiget text’s
ar5iv leg returning a 200 with no extractable prose (the paper was
never converted to HTML). The identifier is valid; only this one
representation is missing. Surfaces as
crate::ErrorCode::TextUnavailable so an agent fetches the PDF
instead of concluding the reference is wrong (issue #302) — NOT
Self::NotFound, which means the id itself does not exist.
A source returned a successful response that contained no file of the
requested kind for doiget source — a PDF-only / single-file
submission (no multi-file bundle), or --figures-only on a submission
with no image files. The identifier is valid; only the bundle / figure
representation is absent. Surfaces as
crate::ErrorCode::TextUnavailable (same “this representation is
missing; the PDF may be fetchable” class as Self::TextUnavailable),
but as a DISTINCT variant so the message is not ar5iv-specific
(issue #343 / ADR-0034; PR review).
Replayed
This session already asked about the ref and got an answer no retry
can change yet (#507, ADR-0057), so it was not asked again. Carries
the code the caller was given then – or RATE_LIMITED when the
earlier answer was retry_after and its wait has not elapsed.
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()
Source§impl From<&FetchError> for ErrorCode
Borrow-form of the collapse above, so a caller that still needs the
error for its Display message / denial_context side-channel
(notably the CLI human-persona renderer, issue #119) can obtain the
closed code without consuming it. The owned impl delegates here so
the mapping table lives in exactly one place.
impl From<&FetchError> for ErrorCode
Borrow-form of the collapse above, so a caller that still needs the
error for its Display message / denial_context side-channel
(notably the CLI human-persona renderer, issue #119) can obtain the
closed code without consuming it. The owned impl delegates here so
the mapping table lives in exactly one place.
Source§fn from(e: &FetchError) -> ErrorCode
fn from(e: &FetchError) -> ErrorCode
Source§impl From<&FetchError> for Option<DenialContext>
impl From<&FetchError> for Option<DenialContext>
Source§fn from(e: &FetchError) -> Self
fn from(e: &FetchError) -> Self
Source§impl From<FetchError> for ErrorCode
Map FetchError to the closed crate::ErrorCode set surfaced at
the public CLI / MCP boundary. Mirrors the
From<RefParseError> for ErrorCode collapse from PR #55.
impl From<FetchError> for ErrorCode
Map FetchError to the closed crate::ErrorCode set surfaced at
the public CLI / MCP boundary. Mirrors the
From<RefParseError> for ErrorCode collapse from PR #55.