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

  1. Audit `Cargo.toml` `[replace]` entries and remove duplicates so only one spec matches any given package.
  2. Narrow each replace spec's version requirement so their match sets are disjoint.
  3. 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

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


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