{"record":{"id":"4860404b6875327e","repo":"jdx/mise","slug":"fetching-url-failed-hint","errorCode":null,"errorMessage":"fetching {url} failed: {}{hint}\n{}","messagePattern":"fetching (.+?) failed: (.+?)(.+?)\n(.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/oci/registry.rs","lineNumber":472,"sourceCode":"                rb = rb.header(\"Authorization\", a);\n            }\n            Ok(rb)\n        })\n        .await\n        .wrap_err_with(|| format!(\"fetching {url}\"))?;\n    let status = resp.status();\n    if !status.is_success() {\n        let hint = if status == StatusCode::UNAUTHORIZED || status == StatusCode::FORBIDDEN {\n            if session.has_credential() {\n                \" — the stored credentials were rejected or lack access to this image\"\n            } else {\n                \" — the image may be private; run `docker login` (or `podman login`) for this registry\"\n            }\n        } else {\n            \"\"\n        };\n        let body = resp.text().await.unwrap_or_default();\n        bail!(\n            \"fetching {url} failed: {}{hint}\\n{}\",\n            status.as_u16(),\n            body.trim()\n        );\n    }\n    let content_type = header_str(&resp, \"content-type\");\n    let body: serde_json::Value = resp\n        .json()\n        .await\n        .wrap_err_with(|| format!(\"parsing JSON response from {url}\"))?;\n    Ok((body, content_type))\n}\n\n/// Retry a transient-failure-prone operation with mise's standard backoff\n/// schedule. Transient means connect/timeout/body errors and 5xx/408/429\n/// statuses surfaced via `error_for_status`. A macro rather than a generic\n/// fn so the operation expression can reborrow `&mut` state (the\n/// [`AuthSession`]) on every attempt.","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/oci/registry.rs#L454-L490","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet manifest = oci.pull_base_image(\"ghcr.io/acme/priv-img:notatag\")?;\n// after (verify tag exists and you are logged in)\n// $ docker login ghcr.io\n// $ docker manifest inspect ghcr.io/acme/priv-img:v1.2.0\nlet manifest = oci.pull_base_image(\"ghcr.io/acme/priv-img:v1.2.0\")?;","handlingStrategy":"try-catch","validationCode":"let status = reqwest::Client::new()\n    .head(&url).send().await.map(|r| r.status());\nif !matches!(status, Ok(s) if s.is_success() || s == StatusCode::UNAUTHORIZED || s == StatusCode::FORBIDDEN) {\n    eprintln!(\"manifest URL unreachable: {status:?}\");\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"fetching\") => {\n        if e.to_string().contains(\"401\") || e.to_string().contains(\"403\") { run_docker_login_hint(); }\n        else if e.to_string().contains(\"429\") { backoff_and_retry(); }\n        else { return Err(e); }\n    }\n    r => r,\n}","preventionTips":["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."],"tags":["network","http","oci","registry"],"backgroundTag":"http-error-response","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}