rust-lang/cargo · error · anyhow::Error
overlapping replacement specifications found: * {} * {}
Error message
overlapping replacement specifications found:
* {}
* {}
both specifications match: {} What it means
Raised when two distinct `[replace]` specifications both match the same resolved package. After matching the first spec, the code checks `potential_matches.next()`; a second match means overlapping replacement rules, which would make the substitution non-deterministic. Cargo rejects this to keep the dependency graph well-defined.
Source
Thrown at src/resolver/dep_cache.rs:177
"replacement specification `{}` matched {} and tried to override it with {}\n\
avoid matching unrelated packages by being more specific",
spec,
summary.version(),
s.version(),
));
}
let replace = if s.source_id() == summary.source_id() {
debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s);
None
} else {
Some(s)
};
let matched_spec = spec.clone();
// Make sure no duplicates
if let Some((spec, _)) = potential_matches.next() {
return Err(anyhow::anyhow!(
"overlapping replacement specifications found:\n\n \
* {}\n * {}\n\nboth specifications match: {}",
matched_spec,
spec,
summary.package_id()
));
}
for dep in summary.dependencies() {
debug!("\t{} => {}", dep.package_name(), dep.version_req());
}
if let Some(r) = replace {
self.used_replacements
.borrow_mut()
.insert(summary.package_id(), r);
}
}
View on GitHub (pinned to 0e07a15537)
Solutions
- Audit `Cargo.toml` `[replace]` entries and remove duplicates so only one spec matches any given package.
- Narrow each replace spec's version requirement so their match sets are disjoint.
- Consolidate into a single `[patch]` entry, which does not have this overlapping-spec restriction.
Example fix
# before
[replace]
"foo:1.0.0" = { path = "../foo" }
"foo:1.*" = { path = "../foo" }
# after
[patch.crates-io]
foo = { path = "../foo" } Defensive patterns
Strategy: validation
Validate before calling
# Lint for overlapping [replace] specs: if grep -c '^".*:.*" = ' Cargo.toml | grep -qw ...; then echo 'check for duplicate/overlapping replace specs'; fi # Better: cargo check will surface the overlap; run it in pre-commit.
Prevention
- Maintain at most one spec per replaced package; remove stale entries.
- Use disjoint version requirements across `[replace]` specs.
- Migrate to `[patch]`, which tolerates overlapping patches deterministically.
When it happens
Trigger: Two `[replace]` entries in `Cargo.toml` whose specs are broad enough that both match one package id — e.g. `[replace] "foo:*"` and `[replace] "foo:1.*"` both matching `foo 1.2.3`. The second `potential_matches.next()` returns `Some`, triggering the bail with both specs and the colliding package id.
Common situations: Accidentally duplicating a replace rule with different specificity; combining a workspace-level and a crate-level `[replace]` for the same package; leftover replace entries after refactoring dependencies.
Related errors
- the replacement specification `{}` matched multiple packages
- replacement specification `{}` matched {} and tried to overr
- subcommand is required, add a subcommand to the command alia
- alias {} has unresolvable recursive definition: {} -> {}
- subcommand is required, but `{alias_name}` is empty
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/7be6cf58a5101f34.json.
Report an issue: GitHub.