rust-lang/cargo · error

patch for ` ` points to the same source, but patches must…

Error message

patch for `{}` points to the same source, but patches must point to different sources
help: check `{}` patch definition for `{}` in `{}`

What it means

A `[patch]` entry must redirect a dependency to a *different* source than the one being patched; a self-referential patch is meaningless. During summary resolution, the registry compares `summary.package_id().source_id().canonical_url()` against the original source's `canonical` URL and bails if they match. This prevents no-op patches that would create resolution loops.

Solutions

  1. Point the patch at a genuinely different source: a local path, fork, or different git URL.
  2. If you only want to pin a version, use `[patch]` with a path to a local checkout rather than the upstream registry.
  3. Double-check the canonical URLs of both the original and patched sources.

Example fix

# before (self-referential)
[patch.crates-io]
foo = { version = "*", path = "../foo" }
# where ../foo's Cargo.toml still sources from crates.io index

# after (distinct local source)
[patch.crates-io]
foo = { path = "../foo-local-fork" }
Defensive patterns

Strategy: validation

Validate before calling

// Before applying a patch, confirm sources differ by canonical URL
fn patch_sources_differ(orig_url: &str, patch_url: &str) -> bool {
    // normalize trailing slashes, scheme, host; then compare
    normalize(orig_url) != normalize(patch_url)
}
// fn normalize(u: &str) -> String { /* strip trailing '/', lowercase host */ }

Try / catch

// When driving cargo programmatically via cargo-the-library:
// match Workspace::new(&root, &config).and_then(|ws| ws.load()).err() {
//     Some(e) if e.to_string().contains("points to the same source") => { /* fix patch */ }
//     _ => {}
// }

Prevention

When it happens

Trigger: `[patch.crates-io] foo = { version = "*", path = "../foo" }` where `../foo` resolves to the same registry/git source as crates-io. Or patching a git dependency to the same git URL.

Common situations: Vendoring a crate that still points back to its origin. Circular workspace references. Misconfigured `[patch]` after moving a crate into the same registry index.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11). Data as JSON: /api/errors/78763b5f350075eb. Report an issue: GitHub.

Appendix: source

Thrown at src/workspace/registry.rs:437

                let (summary, should_unlock) =
                    summary_for_patch(&orig_patch, url, &locked, summaries, source.as_ref())
                        .await?;
                Ok::<_, anyhow::Error>((orig_patch, dep, summary, should_unlock))
            });
        }

        let unlocked_summaries = crate::util::block_on_stream(pending).map(|next| {
            let (orig_patch, dep, summary, should_unlock) = next?;
            debug!(
                "patch summary is {:?} should_unlock={:?}",
                summary, should_unlock
            );
            if let Some(unlock_id) = should_unlock {
                unlock_patches.push(((*orig_patch).clone(), unlock_id));
            }

            if *summary.package_id().source_id().canonical_url() == canonical {
                return Err(anyhow::anyhow!(
                    "patch for `{}` points to the same source, but patches must point to different sources\n\
                    help: check `{}` patch definition for `{}` in `{}`",
                    dep.package_name(),
                    dep.package_name(),
                    url,
                    orig_patch.loc
                ));
            }
            Ok(summary)
        }).collect::<CargoResult<Vec<_>>>()?;

        let mut name_and_version = HashSet::default();
        for summary in unlocked_summaries.iter() {
            let name = summary.package_id().name();
            let version = summary.package_id().version();
            if !name_and_version.insert((name, version)) {
                let duplicate_locations = patch_deps
                    .iter()

View on GitHub (pinned to 98a09e7e7d)