jdx/mise · error
fetching failed
Error message
fetching {url} failed: {}{hint}
{} What it means
Thrown when an HTTP request to fetch an OCI image manifest from a registry returns a non-success status. The error includes the status code, an auth hint when a private image is suspected, and the trimmed response body so the developer can see the registry's reason.
Solutions
- Verify the image URL, repository name, and tag are correct.
- Authenticate with the registry: `docker login` or `podman login`, or set the registry credential env/token.
- If blocked by rate limits, wait or authenticate to raise the limit.
- Inspect the body in the error message — registries often explain the exact rejection there.
Example fix
// before
let manifest = oci.pull_base_image("ghcr.io/acme/priv-img:notatag")?;
// after (verify tag exists and you are logged in)
// $ docker login ghcr.io
// $ docker manifest inspect ghcr.io/acme/priv-img:v1.2.0
let manifest = oci.pull_base_image("ghcr.io/acme/priv-img:v1.2.0")?; Defensive patterns
Strategy: try-catch
Validate before calling
let status = reqwest::Client::new()
.head(&url).send().await.map(|r| r.status());
if !matches!(status, Ok(s) if s.is_success() || s == StatusCode::UNAUTHORIZED || s == StatusCode::FORBIDDEN) {
eprintln!("manifest URL unreachable: {status:?}");
} Try / catch
match result {
Err(e) if e.to_string().contains("fetching") => {
if e.to_string().contains("401") || e.to_string().contains("403") { run_docker_login_hint(); }
else if e.to_string().contains("429") { backoff_and_retry(); }
else { return Err(e); }
}
r => r,
} Prevention
- Log in to the registry before pulling private images.
- Validate image tags with `docker manifest inspect` before automating pulls.
- Use authenticated pulls on Docker Hub to avoid anonymous rate limits.
- Pin image digests instead of mutable tags.
When it happens
Trigger: `fetch_manifest_json` receiving a non-2xx response; called from `pull_base_image`, `resolve_manifest`, and `fetch_remote_image` when pulling/building OCI images from a registry URL.
Common situations: Typo'd image tag or repository that doesn't exist (404); private image without `docker login` (401/403); registry rate limits (429 from Docker Hub); corporate proxy blocking the registry.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- fetching failed
- blob chunk upload failed
- blob upload failed
- fetching blob failed
- fetching current index for
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/4860404b6875327e.
Report an issue: GitHub.
Appendix: source
Thrown at src/oci/registry.rs:472
rb = rb.header("Authorization", a);
}
Ok(rb)
})
.await
.wrap_err_with(|| format!("fetching {url}"))?;
let status = resp.status();
if !status.is_success() {
let hint = if status == StatusCode::UNAUTHORIZED || status == StatusCode::FORBIDDEN {
if session.has_credential() {
" — the stored credentials were rejected or lack access to this image"
} else {
" — the image may be private; run `docker login` (or `podman login`) for this registry"
}
} else {
""
};
let body = resp.text().await.unwrap_or_default();
bail!(
"fetching {url} failed: {}{hint}\n{}",
status.as_u16(),
body.trim()
);
}
let content_type = header_str(&resp, "content-type");
let body: serde_json::Value = resp
.json()
.await
.wrap_err_with(|| format!("parsing JSON response from {url}"))?;
Ok((body, content_type))
}
/// Retry a transient-failure-prone operation with mise's standard backoff
/// schedule. Transient means connect/timeout/body errors and 5xx/408/429
/// statuses surfaced via `error_for_status`. A macro rather than a generic
/// fn so the operation expression can reborrow `&mut` state (the
/// [`AuthSession`]) on every attempt.View on GitHub (pinned to 533346cc37)