jdx/mise · error · eyre::Report

starting blob upload failed: {} {}{}

Error message

starting blob upload failed: {} {}{}

What it means

First step of the OCI blob upload protocol: a POST to initiate an upload session, expecting 202 Accepted (or 201 Created when the blob was cross-repo mounted). Any other non-transient status fails here, decorated with push_auth_hint — either "no credentials found; run docker login" or "credentials rejected or lack push permission (ghcr.io needs write:packages)" plus the response body.

Source

Thrown at src/oci/registry.rs:1321

                let mut rb = HTTP
                    .reqwest()?
                    .post(start_url.as_str())
                    .header("Content-Length", "0");
                if let Some(a) = auth {
                    rb = rb.header("Authorization", a);
                }
                Ok(rb)
            })
            .await
            .wrap_err_with(|| format!("POST {start_url}"))?;
        let status = resp.status();
        match status {
            StatusCode::CREATED => return Ok(UploadOutcome::Mounted),
            StatusCode::ACCEPTED => {}
            s => {
                // Let transient statuses bubble as retryable errors.
                resp.error_for_status_ref()?;
                bail!(
                    "starting blob upload failed: {} {}{}",
                    s.as_u16(),
                    start_url,
                    push_auth_hint(s, had_credential),
                );
            }
        }
        let mut location = self.resolve_location(&resp)?;
        pr.set_position(0);

        // 2. Transfer the bytes.
        if size > UPLOAD_CHUNK_SIZE {
            // Chunked: PATCH each segment, then a zero-length finalizing PUT.
            let mut offset = 0u64;
            while offset < size {
                let len = UPLOAD_CHUNK_SIZE.min(size - offset);
                let err_slot: UploadErrSlot = Default::default();
                let resp = self

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Run `docker login <registry>` (or `podman login`) with credentials that have push permission for the target namespace
  2. For ghcr.io: use a classic PAT with `write:packages` (and `read:packages`), and confirm the package/repo allows your account to write
  3. Sanity-check push rights by pushing a tiny test tag with docker: `docker push <registry>/<repo>:ci-smoke`
  4. Read the body line for the registry's error code (DENIED, NAME_UNKNOWN on ECR requiring pre-created repos, quotas)

Example fix

# before — CI job pushes without auth
mise oci push registry.example.com/acme/app:1

# after — log in with a push-scoped token first
docker login registry.example.com -u $REG_USER -p $REG_TOKEN
mise oci push registry.example.com/acme/app:1
Defensive patterns

Strategy: validation

Validate before calling

# Prove push credentials work before the build/push job:
docker login registry.example.com -u "$REG_USER" -p "$REG_TOKEN"
docker push registry.example.com/acme/ci-smoke:latest  # tiny throwaway image
# ghcr.io: create the PAT with write:packages + read:packages scopes.

Try / catch

// Branch on the auth hint embedded in the message:
let msg = String::from_utf8_lossy(&out.stderr);
if msg.contains("starting blob upload failed") {
    if msg.contains("no credentials were found") {
        // run docker login, then retry the push once
    } else if msg.contains("rejected or lack push permission") {
        // fix token scopes (ghcr: write:packages) or repo ACLs — retrying won't help
    }
}

Prevention

When it happens

Trigger: Pushing without `docker login` to the destination registry (401); ghcr.io token with only read:packages (403); read-only registry credentials; expired stored credentials; registry quotas or denied repository creation.

Common situations: CI pushing to ghcr.io with a PAT missing the write:packages scope; org registries where the account lacks push rights to the repo namespace; first push to a brand-new repository on a registry with restrictive policies.

Related errors


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