dbt-labs/dbt-core · error · anyhow

GET {url} failed: {status}

Error message

GET {url} failed: {status}

What it means

download in crates/dbt-ci/src/sdist.rs performs a GET of a wheel URL and retries transient failures with backoff; when it receives a final non-transient (or retry-exhausted) non-success HTTP status it bails with 'GET {url} failed: {status}'.

Source

Thrown at crates/dbt-ci/src/sdist.rs:222

        match http.get(url).send().await {
            Ok(resp) => {
                let status = resp.status();
                if status.is_success() {
                    return resp
                        .bytes()
                        .await
                        .with_context(|| format!("read body from {url}"));
                }
                if status.is_server_error() && attempt < max_attempts {
                    let delay = backoff(attempt);
                    eprintln!(
                        "warning: GET {url} got {status}; retrying in {}ms",
                        delay.as_millis()
                    );
                    tokio::time::sleep(delay).await;
                    continue;
                }
                bail!("GET {url} failed: {status}");
            }
            Err(e) if is_transient(&e) && attempt < max_attempts => {
                let delay = backoff(attempt);
                eprintln!(
                    "warning: GET {url} failed: {e}; retrying in {}ms",
                    delay.as_millis()
                );
                tokio::time::sleep(delay).await;
                continue;
            }
            Err(e) => return Err(anyhow::Error::new(e).context(format!("GET {url}"))),
        }
    }
}

/// Minimal pyproject wiring up the embedded backend; rich metadata lives in PKG-INFO.
fn render_sdist_pyproject(spec: &Spec, version_pep440: &str) -> String {
    let mut out = String::new();

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Check the status: 404 means fix --download-base-url or upload the wheels first; 403 means fix credentials/permissions for the artifact store.
  2. Verify the exact URL in the message is reachable (curl -I) and that the wheel filename matches what was published.
  3. Retry later if the status is a 5xx — transient cases are already retried internally, so persistent ones need infra attention.
  4. Confirm network egress/proxy settings in CI allow reaching the host.

Example fix

# before
release-sdist build --download-base-url https://example.com/old-path ...
# 404: wheel not there
# after
release-sdist build --download-base-url https://example.com/wheels/1.2.3 ...  # correct path with wheels uploaded first
Defensive patterns

Strategy: retry

Validate before calling

# verify the wheel URL is reachable before the pipeline
url="$BASE_URL/$(basename "$WHEEL")"
curl -fsIL "$url" >/dev/null || { echo "cannot GET $url" >&2; exit 1; }

Try / catch

match download(url).await {
    Err(e) if e.to_string().starts_with("GET ") => {
        eprintln!("wheel download failed permanently: {e:#}");
        std::process::exit(1); // inspect status: 404=wrong URL, 403=auth
    }
    r => r,
}

Prevention

When it happens

Trigger: build_release_sdist downloading a wheel whose GET returns 404 (wrong --download-base-url or missing artifact), 403 (private bucket/registry without credentials), or a persistent 5xx after retries are exhausted.

Common situations: Wheels not yet uploaded (publish order mistake), base URL typo or wrong S3/CodeArtifact path, expired presigned URLs or missing AWS credentials, CDN/proxy returning 5xx consistently.

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/07d88503b585b15b. Report an issue: GitHub.