jdx/mise · error · eyre::Report

blob chunk upload failed: {}{} {}

Error message

blob chunk upload failed: {}{}
{}

What it means

For blobs larger than the upload chunk size, mise PATCHes bytes in chunks and expects 202 Accepted per the OCI dist-spec (201 also accepted because AWS ECR answers Created). A chunk PATCH returning anything else — with auth hint and body — fails the whole upload. Transient 5xx/408/429 were already retried before this line.

Source

Thrown at src/oci/registry.rs:1364

                            offset,
                            len,
                            pr,
                            &err_slot,
                        )
                        // Content-Range is inclusive on both ends.
                        .header("Content-Range", format!("{}-{}", offset, offset + len - 1)))
                    })
                    .await
                    .wrap_err("PATCH blob chunk")?;
                check_upload_err(&err_slot, path)?;
                let status = resp.status();
                // Per the OCI dist-spec a chunk PATCH returns 202 Accepted, but
                // AWS ECR answers with 201 Created. Accept both, as the
                // finalizing PUT below already does.
                if status != StatusCode::ACCEPTED && status != StatusCode::CREATED {
                    resp.error_for_status_ref()?;
                    let body = resp.text().await.unwrap_or_default();
                    bail!(
                        "blob chunk upload failed: {}{}\n{}",
                        status.as_u16(),
                        push_auth_hint(status, had_credential),
                        body.trim(),
                    );
                }
                location = self.resolve_location(&resp).unwrap_or(location);
                offset += len;
            }
            // Finalize with ?digest=…
            let mut put_url = location;
            put_url.query_pairs_mut().append_pair("digest", digest);
            let resp = self
                .session
                .send(|auth| {
                    let mut rb = HTTP
                        .reqwest()?
                        .put(put_url.as_str())

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Simply re-run the push — a fresh upload session usually completes if the first died of session/token expiry
  2. Shrink the pushed layers (smaller base, fewer bundled tools) so the upload finishes within the registry's session lifetime
  3. For 401 mid-upload: use a longer-lived token or re-login immediately before pushing
  4. Check the body for registry-specific codes (BLOB_UPLOAD_INVALID, DIGEST_INVALID) pointing at range/digest mismatches
Defensive patterns

Strategy: retry

Validate before calling

# Reduce exposure to chunked-upload failures before pushing:
# - keep layers small (smaller bases, fewer bundled toolchains)
# - verify egress allows large PATCH requests through proxies:
curl -sS -o /dev/null -w '%{http_code}\n' -X PATCH https://registry.example.com/v2/ # expect non-5xx routing response

Try / catch

// Chunk failures are usually session/token expiry — one bounded retry helps:
for attempt in 1..=2 {
    match run_mise_oci_push().await {
        Ok(_) => break,
        Err(e) if e.to_string().contains("blob chunk upload failed") && attempt < 2 => {
            relogin_if_needed().await; // refresh short-lived tokens
            tokio::time::sleep(Duration::from_secs(10)).await;
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: The upload session Location URL expiring mid-transfer on slow links (registries kill idle/long sessions); an auth token expiring between chunks (401); Content-Range mismatch after a retry re-sent a chunk; intermediate proxies rejecting PATCH.

Common situations: Pushing large toolchain layers (100s of MB) over slow or proxy-intercepted CI networks; long uploads against registries with short session TTLs (some ECR/Zot configurations).

Related errors


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