{"id":"a17a5b54c9851e43","repo":"rust-lang/cargo","slug":"package-collision-in-the-lockfile-packages-and","errorCode":null,"errorMessage":"package collision in the lockfile: packages {} and {} are different, but only one can be written to lockfile unambiguously","messagePattern":"package collision in the lockfile: packages (.+?) and (.+?) are different, but only one can be written to lockfile unambiguously","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/resolver/mod.rs","lineNumber":1074,"sourceCode":"        }\n\n        visited.remove(&id);\n        Ok(())\n    }\n}\n\n/// Checks that packages are unique when written to lock file.\n///\n/// When writing package ID's to lock file, we apply lossy encoding. In\n/// particular, we don't store paths of path dependencies. That means that\n/// *different* packages may collide in the lock file, hence this check.\nfn check_duplicate_pkgs_in_lockfile(resolve: &Resolve) -> CargoResult<()> {\n    let mut unique_pkg_ids = HashMap::default();\n    let state = encode::EncodeState::new(resolve);\n    for pkg_id in resolve.iter() {\n        let encodable_pkd_id = encode::encodable_package_id(pkg_id, &state, resolve.version());\n        if let Some(prev_pkg_id) = unique_pkg_ids.insert(encodable_pkd_id, pkg_id) {\n            anyhow::bail!(\n                \"package collision in the lockfile: packages {} and {} are different, \\\n                 but only one can be written to lockfile unambiguously\",\n                prev_pkg_id,\n                pkg_id\n            )\n        }\n    }\n    Ok(())\n}\n","sourceCodeStart":1056,"sourceCodeEnd":1084,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/resolver/mod.rs#L1056-L1084","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Bump the version of one of the colliding crates so they differ (e.g. `1.0.0` → `1.0.1`).","Consolidate both dependencies to point at the same single source location.","If one copy is vendored, remove the duplicate path dependency and use the canonical one."],"exampleFix":"# before: two path deps both named foo v1.0.0 at different paths\n# after\n# edit one fork's Cargo.toml: version = \"1.0.1\"","handlingStrategy":"validation","validationCode":"# In CI, ensure no two path deps share name+version:\ncargo metadata --no-deps --format-version 1 | \\\n  jq '.packages | group_by(.name + .version) | map(select(length > 1)) | length' \\\n  | grep -qw 0 || echo 'duplicate name+version path packages'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give internal crates unique versions per source location.","Avoid vendoring the same crate from two paths.","Consolidate duplicate path deps to a single canonical source."],"tags":["lockfile","collision","path-dependency","workspace"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}