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
- Read the body line — registries name the exact code (MANIFEST_INVALID, TAG_INVALID, DENIED, BLOB_UNKNOWN) which determines the fix
- For immutable-tag rejections: push a new tag/version instead of overwriting
- 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)
- 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
- Push immutable unique tags (git SHA, build number); never reuse released versions
- Ensure all blobs finish uploading before the manifest step by letting mise drive the full push (no partial manual uploads)
- Read the registry's error code in the message body — it names the exact policy or schema violation
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
- fetching {manifest_url} failed: {}
- starting blob upload failed: {} {}{}
- fetching {url} failed: {}{hint} {}
- blob chunk upload failed: {}{} {}
- blob upload failed: {}{} {}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/68d826414cb6ad40.
Report an issue: GitHub.