rust-lang/cargo · error · anyhow::Error

package collision in the lockfile: packages {} and {} are di

Error message

package collision in the lockfile: packages {} and {} are different, but only one can be written to lockfile unambiguously

What it means

Produced by `check_duplicate_pkgs_in_lockfile`: two genuinely different `PackageId`s encode to the same lossy lockfile representation (the lockfile omits path-dependency paths, so two distinct path/git packages with same name+version+source-type collapse to one encodable ID). Cargo refuses to write an ambiguous lockfile.

Source

Thrown at src/resolver/mod.rs:1074

        }

        visited.remove(&id);
        Ok(())
    }
}

/// Checks that packages are unique when written to lock file.
///
/// When writing package ID's to lock file, we apply lossy encoding. In
/// particular, we don't store paths of path dependencies. That means that
/// *different* packages may collide in the lock file, hence this check.
fn check_duplicate_pkgs_in_lockfile(resolve: &Resolve) -> CargoResult<()> {
    let mut unique_pkg_ids = HashMap::default();
    let state = encode::EncodeState::new(resolve);
    for pkg_id in resolve.iter() {
        let encodable_pkd_id = encode::encodable_package_id(pkg_id, &state, resolve.version());
        if let Some(prev_pkg_id) = unique_pkg_ids.insert(encodable_pkd_id, pkg_id) {
            anyhow::bail!(
                "package collision in the lockfile: packages {} and {} are different, \
                 but only one can be written to lockfile unambiguously",
                prev_pkg_id,
                pkg_id
            )
        }
    }
    Ok(())
}

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Bump the version of one of the colliding crates so they differ (e.g. `1.0.0` → `1.0.1`).
  2. Consolidate both dependencies to point at the same single source location.
  3. If one copy is vendored, remove the duplicate path dependency and use the canonical one.

Example fix

# before: two path deps both named foo v1.0.0 at different paths
# after
# edit one fork's Cargo.toml: version = "1.0.1"
Defensive patterns

Strategy: validation

Validate before calling

# In CI, ensure no two path deps share name+version:
cargo metadata --no-deps --format-version 1 | \
  jq '.packages | group_by(.name + .version) | map(select(length > 1)) | length' \
  | grep -qw 0 || echo 'duplicate name+version path packages'

Prevention

When it happens

Trigger: Two workspace path dependencies, or two git checkouts, sharing the same crate name and version but at different filesystem locations — e.g. `dep = { path = "vendor/a/foo" }` and another crate depending on `dep = { path = "vendor/b/foo" }`, both `foo 1.0.0`. The `unique_pkg_ids.insert` collision triggers the bail.

Common situations: Vendoring the same crate version from two locations; monorepo with multiple copies of an internal crate at the same version; git submodules duplicating a crate; `[patch]` targets that resolve to a name/version clashing with an existing path dep.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/a17a5b54c9851e43.json. Report an issue: GitHub.