jdx/mise · error · eyre::Report

manifest push failed: {} {url}{} {}

Error message

manifest push failed: {} {url}{}
{}

What it means

The final manifest PUT that tags the pushed image. A non-success status fails here with the HTTP code, auth hint, and the registry's response body. This is where registry-side manifest validation and policy enforcement (MANIFEST_INVALID, DENIED, tag immutability, missing blobs) surface.

Source

Thrown at src/oci/registry.rs:1475

        let resp = self
            .session
            .send(|auth| {
                let mut rb = HTTP
                    .reqwest()?
                    .put(&url)
                    .header("Content-Type", media_type)
                    .body(body.clone());
                if let Some(a) = auth {
                    rb = rb.header("Authorization", a);
                }
                Ok(rb)
            })
            .await
            .wrap_err_with(|| format!("PUT {url}"))?;
        let status = resp.status();
        if !status.is_success() {
            let body = resp.text().await.unwrap_or_default();
            bail!(
                "manifest push failed: {} {url}{}\n{}",
                status.as_u16(),
                push_auth_hint(status, had_credential),
                body.trim(),
            );
        }
        Ok(())
    }

    /// Point `tag` at an OCI image index containing `entry` plus whatever
    /// other-platform entries the tag already carries. Returns the digest of
    /// the pushed index.
    ///
    /// NOTE: read-modify-write without registry-side concurrency control (the
    /// Distribution spec has no conditional manifest PUT), so two runners
    /// updating the same tag at the same instant can race — sequence
    /// per-platform pushes in CI when that matters.
    async fn update_tag_index(&mut self, tag: &str, entry: Descriptor) -> Result<String> {

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Read the body line — registries name the exact code (MANIFEST_INVALID, TAG_INVALID, DENIED, BLOB_UNKNOWN) which determines the fix
  2. For immutable-tag rejections: push a new tag/version instead of overwriting
  3. For BLOB_UNKNOWN: re-run the full push so all layers upload before the manifest (or verify a prior partial push did not half-complete)
  4. For permission errors: confirm the credential has push scope on the repository namespace (ghcr.io: write:packages)

Example fix

# before — overwriting an immutable tag
mise oci push registry.example.com/acme/app:1.2.3

# after — push a new tag
mise oci push registry.example.com/acme/app:1.2.4
Defensive patterns

Strategy: try-catch

Validate before calling

# Before pushing to a protected tag, check the registry's immutability rules
# and prefer unique tags per build:
TAG="$(git rev-parse --short HEAD)"
mise oci push registry.example.com/acme/app:"$TAG"   # unique → policy-safe
# Verify the manifest validates upstream first:
crane validate --remote registry.example.com/acme/app:"$TAG" 2>/dev/null || true

Try / catch

// Branch on the registry error code embedded in the body:
let msg = String::from_utf8_lossy(&out.stderr);
if msg.contains("manifest push failed") {
    let upper = msg.to_uppercase();
    if upper.contains("DENIED") && msg.contains("immutab") || msg.contains("cannot be overwritten") {
        // push a new tag instead of overwriting
    } else if upper.contains("MANIFEST_INVALID") {
        // schema/media-type issue — check base image manifest type, report to mise
    } else if upper.contains("BLOB_UNKNOWN") {
        // re-push so all layers upload before the manifest
    } else if msg.contains("401") || msg.contains("403") {
        // fix push scopes / docker login, then retry
    }
}

Prevention

When it happens

Trigger: Pushing to a tag protected by an immutability policy (409/400 DENIED); a manifest referencing blobs the registry thinks are missing; schema/media-type rejections from older registries; insufficient permission on the tag namespace; subject/referrers constraints.

Common situations: Retagging an already-published version protected by an immutable-tag rule (common on Harbor/ECR); mixed-registry pushes where a proxy cached blob state; org policies restricting latest.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/68d826414cb6ad40. Report an issue: GitHub.