rust-lang/cargo · error
multiple registries are configured with the same index url
Error message
multiple registries are configured with the same index url '{}': {} What it means
Cargo resolves a registry `SourceId` back to a configured registry name (for credential lookup). It collects candidate names from env vars (`CARGO_REGISTRIES_<NAME>_INDEX`) and then from `[registries.*]` config. If two or more configured registries share the same canonical index URL, the mapping is ambiguous and Cargo bails, listing the colliding names.
Solutions
- Remove the duplicate registry definition so only one name maps to each index URL.
- If you need an alias, use `[source.<alias>] registry = "<canonical-name>"` (a source alias) instead of a second `[registries.<name>]` with the same index.
- Unset any `CARGO_REGISTRIES_<NAME>_INDEX` env var that duplicates a config entry's URL.
- Run `cargo config get registries` to list all configured registries and identify the collision.
Example fix
# before: two registries, same index [registries.mirror] index = "sparse+https://crates.io/index/" [registries.upstream] index = "sparse+https://crates.io/index/" # after: alias via source, single registry [registries.mirror] index = "sparse+https://crates.io/index/" [source.upstream] registry = "mirror"
Defensive patterns
Strategy: validation
Validate before calling
fn registries_unique_indexes(config: &toml::Value) -> Result<(), anyhow::Error> {
let mut seen = std::collections::HashSet::new();
if let Some(regs) = config.get("registries").and_then(|v| v.as_table()) {
for (name, v) in regs {
if let Some(idx) = v.get("index").and_then(|s| s.as_str()) {
if !seen.insert(idx.to_string()) {
anyhow::bail!("duplicate index across registries: {idx} (at {name})");
}
}
}
}
Ok(())
} Type guard
fn registry_indexes_unique(config: &toml::Value) -> bool {
let mut s = std::collections::HashSet::new();
config.get("registries").and_then(|v| v.as_table()).map_or(true, |t|
t.values().filter_map(|v| v.get("index").and_then(|i| i.as_str())).all(|i| s.insert(i.to_string())))
} Try / catch
match auth::registry_name_from_sid(&sid, gctx) {
Ok(name) => Ok(name),
Err(e) if e.to_string().contains("same index url") => {
// guide user to dedupe; fall back to explicit --registry <name>
Err(anyhow!("resolve the registry collision by passing --registry explicitly or removing the duplicate config"))
}
Err(e) => Err(e),
} Prevention
- Use `[source.<alias>] registry = "<name>"` to alias, not duplicate `[registries.*]`.
- Audit `.cargo/config.toml` for duplicate index URLs.
- Unset redundant `CARGO_REGISTRIES_<NAME>_INDEX` env vars.
- Pass `--registry <name>` explicitly to disambiguate when needed.
When it happens
Trigger: In `auth::registry_name_from_sid`, after gathering names whose index URL canonicalizes to the same value as the source's, `names.len() > 1`. Triggered by defining two `[registries.<name>]` entries (or env + config) with identical (or canonical-equivalent) `index` URLs.
Common situations: User aliases the same registry under two names (e.g. a corporate mirror and the original); leftover config from a rename where both old and new point at the same index; env var (`CARGO_REGISTRIES_X_INDEX`) duplicating a config-level entry pointing at the same URL.
Related errors
- no credential providers could handle the request
- config.json not found
- credential process ` ` failed with status
- local registry index path is not a directory
- local registry path is not a directory
AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11).
Data as JSON: /api/errors/1b07d3387be6d838.
Report an issue: GitHub.
Appendix: source
Thrown at src/util/auth/mod.rs:193
// Discover names from the configuration only if none were found in the environment.
if names.len() == 0 {
if let Some(registries) = gctx.values()?.get("registries") {
let (registries, _) = registries.table("registries")?;
for (name, value) in registries {
if let Some(v) = value.table(&format!("registries.{name}"))?.0.get("index") {
let (v, _) = v.string(&format!("registries.{name}.index"))?;
if index == &CanonicalUrl::new(&v.into_url()?)? {
names.push(name.clone());
}
}
}
}
}
names.sort();
match names.len() {
0 => None,
1 => Some(std::mem::take(&mut names[0])),
_ => anyhow::bail!(
"multiple registries are configured with the same index url '{}': {}",
&sid.as_url(),
names.join(", ")
),
}
};
// It's possible to have a registry configured in a Cargo config file,
// then override it with configuration from environment variables.
// If the name doesn't match, leave a note to help the user understand
// the potentially confusing situation.
if let Some(name) = name.as_deref() {
if Some(name) != sid.alt_registry_key() {
gctx.shell().note(format!(
"name of alternative registry `{}` set to `{name}`",
sid.url()
))?
}View on GitHub (pinned to 98a09e7e7d)