{"record":{"id":"78763b5f350075eb","repo":"rust-lang/cargo","slug":"patch-for-points-to-the-same-source-but-patc","errorCode":null,"errorMessage":"patch for `{}` points to the same source, but patches must point to different sources\nhelp: check `{}` patch definition for `{}` in `{}`","messagePattern":"patch for `(.+?)` points to the same source, but patches must point to different sources\nhelp: check `(.+?)` patch definition for `(.+?)` in `(.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/workspace/registry.rs","lineNumber":437,"sourceCode":"                let (summary, should_unlock) =\n                    summary_for_patch(&orig_patch, url, &locked, summaries, source.as_ref())\n                        .await?;\n                Ok::<_, anyhow::Error>((orig_patch, dep, summary, should_unlock))\n            });\n        }\n\n        let unlocked_summaries = crate::util::block_on_stream(pending).map(|next| {\n            let (orig_patch, dep, summary, should_unlock) = next?;\n            debug!(\n                \"patch summary is {:?} should_unlock={:?}\",\n                summary, should_unlock\n            );\n            if let Some(unlock_id) = should_unlock {\n                unlock_patches.push(((*orig_patch).clone(), unlock_id));\n            }\n\n            if *summary.package_id().source_id().canonical_url() == canonical {\n                return Err(anyhow::anyhow!(\n                    \"patch for `{}` points to the same source, but patches must point to different sources\\n\\\n                    help: check `{}` patch definition for `{}` in `{}`\",\n                    dep.package_name(),\n                    dep.package_name(),\n                    url,\n                    orig_patch.loc\n                ));\n            }\n            Ok(summary)\n        }).collect::<CargoResult<Vec<_>>>()?;\n\n        let mut name_and_version = HashSet::default();\n        for summary in unlocked_summaries.iter() {\n            let name = summary.package_id().name();\n            let version = summary.package_id().version();\n            if !name_and_version.insert((name, version)) {\n                let duplicate_locations = patch_deps\n                    .iter()","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/rust-lang/cargo/blob/98a09e7e7d62850f14e5b6132101fc1edd19a16f/src/workspace/registry.rs#L419-L455","documentation":"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.","triggerScenarios":"`[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.","commonSituations":"Vendoring a crate that still points back to its origin. Circular workspace references. Misconfigured `[patch]` after moving a crate into the same registry index.","solutions":["Point the patch at a genuinely different source: a local path, fork, or different git URL.","If you only want to pin a version, use `[patch]` with a path to a local checkout rather than the upstream registry.","Double-check the canonical URLs of both the original and patched sources."],"exampleFix":"# before (self-referential)\n[patch.crates-io]\nfoo = { version = \"*\", path = \"../foo\" }\n# where ../foo's Cargo.toml still sources from crates.io index\n\n# after (distinct local source)\n[patch.crates-io]\nfoo = { path = \"../foo-local-fork\" }","handlingStrategy":"validation","validationCode":"// Before applying a patch, confirm sources differ by canonical URL\nfn patch_sources_differ(orig_url: &str, patch_url: &str) -> bool {\n    // normalize trailing slashes, scheme, host; then compare\n    normalize(orig_url) != normalize(patch_url)\n}\n// fn normalize(u: &str) -> String { /* strip trailing '/', lowercase host */ }","typeGuard":null,"tryCatchPattern":"// When driving cargo programmatically via cargo-the-library:\n// match Workspace::new(&root, &config).and_then(|ws| ws.load()).err() {\n//     Some(e) if e.to_string().contains(\"points to the same source\") => { /* fix patch */ }\n//     _ => {}\n// }","preventionTips":["Always patch to a distinct source (local path or fork).","Review `[patch]` URLs for accidental self-references.","Avoid patching a registry dep to the same registry."],"tags":["cargo","patch","registry","source-resolution","config"],"backgroundTag":null,"analyzedSha":"98a09e7e7d62850f14e5b6132101fc1edd19a16f","analyzedAt":"2026-08-11T17:42:36.556Z","contentChangedAt":"2026-08-11T17:42:36.556Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}