dbt-labs/dbt-core · error · anyhow

{filename}'s Requires-Dist disagrees with the sdist: sdist d

Error message

{filename}'s Requires-Dist disagrees with the sdist: sdist deps={:?}, wheel deps={:?}

What it means

The wheel's METADATA Requires-Dist set must exactly equal the dependencies declared in the sdist's pyproject. This bail fires when the sets differ (added, removed, or differently-specified dependencies), catching wheels built from a different dependency set than the sdist.

Source

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

    let expected_python = spec.requires_python.as_deref();
    let actual_python = metadata.requires_python.as_deref();
    if actual_python != expected_python {
        bail!(
            "{filename} declares Requires-Python {actual:?} but the sdist says \
             {expected:?}; point `--pyproject-dir` at the pyproject that built \
             these wheels",
            actual = actual_python.unwrap_or("(absent)"),
            expected = expected_python.unwrap_or("(absent)"),
        );
    }

    let expected_deps: std::collections::BTreeSet<&str> =
        spec.dependencies.iter().map(|d| d.trim()).collect();
    let actual_deps: std::collections::BTreeSet<&str> =
        metadata.requires_dist.iter().map(|d| d.trim()).collect();
    if expected_deps != actual_deps {
        bail!(
            "{filename}'s Requires-Dist disagrees with the sdist: sdist deps={:?}, \
             wheel deps={:?}",
            expected_deps,
            actual_deps,
        );
    }
    Ok(())
}

/// The `*.dist-info/METADATA` bytes from a wheel held in memory.
fn wheel_metadata(wheel: &[u8]) -> Result<Option<Vec<u8>>> {
    let mut archive = zip::ZipArchive::new(Cursor::new(wheel)).context("open wheel as zip")?;
    let name = archive
        .file_names()
        .find(|n| {
            n.ends_with("/METADATA")
                && n.split('/')
                    .next()

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Rebuild the wheels from the same pyproject as the sdist so Requires-Dist matches exactly.
  2. Point --pyproject-dir at the pyproject that actually built these wheels.
  3. Diff the two dep lists printed in the error and reconcile pyproject.toml (add missing deps or update version specifiers), then rebuild.

Example fix

# before
sdist deps: {"click>=8", "pydantic>=2"}
wheel deps: {"click>=8"}
# after
add pydantic>=2 to the wheel build (rebuild wheels from current pyproject.toml)
Defensive patterns

Strategy: validation

Validate before calling

# compare wheel deps vs pyproject deps before the release step
python -c "import tomllib,sys; print(sorted(tomllib.load(open('pyproject.toml','rb'))['project']['dependencies']))"
unzip -p wheel/*.whl '*/METADATA' | grep '^Requires-Dist:' | sort

Try / catch

if let Err(e) = check_wheel_metadata_agrees(...) {
    if e.to_string().contains("Requires-Dist") {
        eprintln!("dependency drift between sdist and wheels; rebuild wheels: {e:#}");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: check_wheel_metadata_agrees normalizes both dependency lists into trimmed BTreeSets and bails when they are not equal — e.g. wheel built before a new dependency was added to pyproject, or wheel extras/markers formatted differently after trimming.

Common situations: Adding/removing a dependency and reusing stale wheels; --pyproject-dir pointing at an older/newer copy of the project; dependency strings differing only in whitespace is tolerated, but different version specifiers or markers are not.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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