dbt-labs/dbt-core · error · anyhow

upload {filename} failed: {status} {body}

Error message

upload {filename} failed: {status}
{body}

What it means

This error is raised by upload_dist in crates/dbt-ci/src/publish.rs when an artifact upload (to CodeArtifact or PyPI) fails with a non-success HTTP status that is not recognized as an 'already exists' condition, after all retry attempts for transient failures are exhausted. The bail includes the HTTP status and the response body so the developer can see the registry's actual rejection reason.

Source

Thrown at crates/dbt-ci/src/publish.rs:435

                    return Ok(());
                }
                if status.is_server_error() && attempt < max_attempts {
                    let delay = backoff(attempt);
                    eprintln!(
                        "warning: upload attempt {attempt}/{max_attempts} for {filename} got {status}; retrying in {}ms",
                        delay.as_millis(),
                    );
                    tokio::time::sleep(delay).await;
                    continue;
                }
                let body = resp.text().await.unwrap_or_default();
                if is_already_exists(status, &body) {
                    eprintln!(
                        "• {filename} already published at {url}; treating as success ({status})"
                    );
                    return Ok(());
                }
                bail!("upload {filename} failed: {status}\n{body}");
            }
            Err(e) if is_transient(&e) && attempt < max_attempts => {
                let delay = backoff(attempt);
                eprintln!(
                    "warning: upload attempt {attempt}/{max_attempts} for {filename} failed: {e}; retrying in {}ms",
                    delay.as_millis(),
                );
                tokio::time::sleep(delay).await;
                continue;
            }
            Err(e) => {
                return Err(anyhow::Error::new(e).context(format!("POST {url}")));
            }
        }
    }
}

fn build_upload_form(

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Inspect the status and body in the message: 401/403 means refresh registry credentials (e.g. aws codeartifact login or pip keyring auth) before retrying.
  2. If the version already exists but wasn't detected as such, bump the version or fix is_already_exists patterns to match your registry's duplicate message.
  3. Retest connectivity/proxy settings if the status is 5xx or a gateway error.
  4. Verify the artifact itself (correct filename, complete wheel/sdist) matches what the registry expects for the project name and version.

Example fix

// before
upload_dist(...).unwrap();
// after
if let Err(e) = upload_dist(...) {
    eprintln!("publish failed (check registry auth/version): {e:#}");
    std::process::exit(1);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: check auth + duplicate status before a long publish run
fn preflight_publish(registry: &str, version: &str) -> anyhow::Result<()> {
    anyhow::ensure!(!version.is_empty(), "version required");
    // verify credentials early, e.g. `aws codeartifact get-authorization-token` or `twine check`
    Ok(())
}

Try / catch

match upload_dist(...) {
    Ok(()) => {},
    Err(e) if e.to_string().contains("upload") => {
        eprintln!("registry rejected upload, check auth/status: {e:#}");
        std::process::exit(1);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling upload_codeartifact or upload_pypi with a file whose upload request returns a 4xx/5xx status (e.g. 401 unauthorized, 403 forbidden, 400 bad request) that is not matched by is_already_exists, and where the error is not transient or retries are exhausted.

Common situations: Expired or missing registry credentials, uploading a package version that is rejected (immutable version, name mismatch), network/proxy failures that are non-transient, or the registry rejecting a malformed artifact (e.g. wrong filename or broken twine metadata).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/ec980105b2252fb1. Report an issue: GitHub.