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 = selfView on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Run `docker login <registry>` (or `podman login`) with credentials that have push permission for the target namespace
- For ghcr.io: use a classic PAT with `write:packages` (and `read:packages`), and confirm the package/repo allows your account to write
- Sanity-check push rights by pushing a tiny test tag with docker: `docker push <registry>/<repo>:ci-smoke`
- 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
- Verify push scopes at CI start with a tiny smoke push, not during the real build
- For ghcr.io, use a PAT with write:packages; check org package settings grant write access
- Pre-create repositories on registries that require it (AWS ECR)
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
- blob chunk upload failed: {}{} {}
- blob upload failed: {}{} {}
- manifest push failed: {} {url}{} {}
- fetching {url} failed: {}{hint} {}
- fetching {manifest_url} failed: {}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/764c4910f84543ce.
Report an issue: GitHub.