{"record":{"id":"265e25e883b7135a","repo":"astral-sh/uv","slug":"multiple-index-urls-specified-existing-vs","errorCode":null,"errorMessage":"Multiple index URLs specified: `{existing}` vs. `{index_url}`","messagePattern":"Multiple index URLs specified: `(.+?)` vs\\. `(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/uv-requirements/src/specification.rs","lineNumber":583,"sourceCode":"                        \"Multiple `pylock.toml` files specified: `{}` vs. `{}`\",\n                        existing.user_display(),\n                        pylock.user_display()\n                    ));\n                }\n                spec.pylock = Some(pylock);\n            }\n\n            // Use the first project name discovered.\n            if spec.project.is_none() {\n                spec.project = source.project;\n            }\n\n            if let Some(index_url) = source.index_url {\n                if let Some(existing) = spec.index_url\n                    && CanonicalUrl::new(index_url.url().clone())\n                        != CanonicalUrl::new(existing.url().clone())\n                {\n                    return Err(anyhow::anyhow!(\n                        \"Multiple index URLs specified: `{existing}` vs. `{index_url}`\",\n                    ));\n                }\n                spec.index_url = Some(index_url);\n            }\n            spec.no_index |= source.no_index;\n            spec.extra_index_urls.extend(source.extra_index_urls);\n            spec.find_links.extend(source.find_links);\n            spec.no_binary.extend(source.no_binary);\n            spec.no_build.extend(source.no_build);\n            spec.require_hashes |= source.require_hashes;\n        }\n\n        // Read all constraints, treating both requirements _and_ constraints as constraints.\n        // Overrides are ignored.\n        for source in constraints {\n            let source = Self::from_source_with_cache(source, client_builder, &mut cache).await?;\n            for entry in source.requirements {","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/astral-sh/uv/blob/f1a42680ff5272232d65748acf338b19778dde24/crates/uv-requirements/src/specification.rs#L565-L601","documentation":"Thrown during RequirementsSpecification merging of plain requirements sources: if the accumulated spec already has an index_url and a new source also defines one whose CanonicalUrl differs, uv refuses to continue. CanonicalUrl comparison ignores trivial URL differences (trailing slashes, default ports), so this only fires for genuinely different indexes.","triggerScenarios":"Combining `--index-url` on the CLI with a requirements.txt containing its own `--index-url` line pointing elsewhere; concatenating two requirements files each declaring a different `--index-url`; feeding `-r a.txt -r b.txt` where both pin incompatible indexes.","commonSituations":"A private mirror index configured globally (uv.toml or env) colliding with an index pinned inside a vendored requirements file; copy-pasting requirements files between projects that target different internal mirrors; a lock/requirements export that embeds `--index-url` while the user also passes one explicitly.","solutions":["Pick one canonical index: delete the `--index-url` line from the requirements file or drop the CLI/config flag, so only one remains.","If you need multiple indexes, move the secondary one to `--extra-index-url` / `[[index]]` entries, which are allowed to accumulate.","Verify the two URLs really are the same index after redirects; if they are, make the strings identical (or canonicalize trailing slash) so CanonicalUrl comparison passes."],"exampleFix":"# before (reqs.txt has: --index-url https://pypi.org/simple)\nuv pip compile --index-url https://mirror.internal/simple -r reqs.txt\n# after\nuv pip compile --extra-index-url https://mirror.internal/simple -r reqs.txt","handlingStrategy":"validation","validationCode":"# Rust: canonicalize and compare index URLs before merging requirement sources\nuse uv_distribution_types::CanonicalUrl;\n\nfn assert_single_index(urls: Vec<Option<IndexUrl>>) -> anyhow::Result<Option<IndexUrl>> {\n    let mut acc: Option<IndexUrl> = None;\n    for url in urls.into_iter().flatten() {\n        if let Some(existing) = &acc {\n            if CanonicalUrl::new(url.url().clone()) != CanonicalUrl::new(existing.url().clone()) {\n                anyhow::bail!(\"index conflict: {existing} vs {url}\");\n            }\n        } else {\n            acc = Some(url);\n        }\n    }\n    Ok(acc)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare the primary index in exactly one layer (CLI, config, or file) and use --extra-index-url for the rest.","Grep requirements/constraint files for `--index-url` lines before feeding them alongside CLI index flags.","Remember trailing slashes and default ports are normalized away; real differences in host/path are what trigger this."],"tags":["index","requirements","configuration","merge"],"backgroundTag":null,"analyzedSha":"f1a42680ff5272232d65748acf338b19778dde24","analyzedAt":"2026-08-16T04:51:47.599Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}