astral-sh/uv · error
Multiple `pylock.toml` files specified: `{}` vs. `{}`
Error message
Multiple `pylock.toml` files specified: `{}` vs. `{}` What it means
Thrown while merging multiple requirement sources (CLI requirements, requirements.txt, constraints, overrides) into a single RequirementsSpecification. uv allows at most one pylock.toml across all merged sources; when a second source also carries a pylock (e.g., a second `--pylock` reference or a requirements file that itself pins a pylock.toml), the merge aborts. The first (existing) and conflicting paths are both printed.
Source
Thrown at crates/uv-requirements/src/specification.rs:564
}
// Read all requirements, and keep track of all requirements _and_ constraints.
// A `requirements.txt` can contain a `-c constraints.txt` directive within it, so reading
// a requirements file can also add constraints.
for source in requirement_sources {
spec.requirements.extend(source.requirements);
spec.constraints.extend(source.constraints);
spec.overrides.extend(source.overrides);
spec.override_dependencies
.extend(source.override_dependencies);
spec.excludes.extend(source.excludes);
spec.extras.extend(source.extras);
spec.source_trees.extend(source.source_trees);
// Allow at most one `pylock.toml`.
if let Some(pylock) = source.pylock {
if let Some(existing) = spec.pylock {
return Err(anyhow::anyhow!(
"Multiple `pylock.toml` files specified: `{}` vs. `{}`",
existing.user_display(),
pylock.user_display()
));
}
spec.pylock = Some(pylock);
}
// Use the first project name discovered.
if spec.project.is_none() {
spec.project = source.project;
}
if let Some(index_url) = source.index_url {
if let Some(existing) = spec.index_url
&& CanonicalUrl::new(index_url.url().clone())
!= CanonicalUrl::new(existing.url().clone())
{View on GitHub (pinned to f1a42680ff)
Solutions
- Remove one of the two pylock references named in the message so only a single pylock.toml is supplied per invocation.
- If both are needed at different times, split the work into two separate uv commands instead of merging sources.
- Regenerate the requirements source (without embedded pylock metadata) if it was produced by a tool that recorded the lock automatically.
Example fix
# before uv pip compile --pylock pylock.toml -r reqs-with-pylock.txt # after uv pip compile --pylock pylock.toml -r reqs.txt # reqs.txt no longer references a pylock
Defensive patterns
Strategy: validation
Validate before calling
# Rust: before merging sources, assert at most one pylock
let pylocks: Vec<_> = sources
.iter()
.filter_map(|s| s.pylock.as_ref())
.collect();
if pylocks.len() > 1 {
return Err(anyhow::anyhow!(
"refusing to merge: multiple pylock.toml sources: {}",
pylocks.iter().map(|p| p.user_display().to_string()).collect::<Vec<_>>().join(", ")
));
} Prevention
- Keep exactly one source of lock truth per uv invocation; never pass a pylock via both a file and a flag.
- When layering requirement files in scripts, grep them for pylock references before combining.
- Document in CI which artifact is the lock input so future edits don't silently add a second one.
When it happens
Trigger: Passing two files that each reference a pylock.toml to `uv pip compile`/`uv sync`/`uv lock` (e.g., `--requirements a/pylock.toml --requirements b/pylock.toml`), or combining `-r requirements.txt` (which records a pylock) with an explicit `--pylock pylock.toml` on the same invocation.
Common situations: Scripts that layer a lockfile on top of a requirements file that already embeds lock metadata; CI pipelines upgrading to a setup where pylock.toml is auto-discovered plus an explicit flag; migrating from one pylock location to another while the old one is still listed in config.
Related errors
- Multiple index URLs specified: `{existing}` vs. `{index_url}
- pip-compile's `--config` is unsupported (uv does not use a c
- pip-compile's `--emit-options` is unsupported (try `--emit-b
- pip-sync's `--config` is unsupported (uv does not use a conf
- Cannot specify additional requirements alongside a `pylock.t
AI-assisted analysis of astral-sh/uv@f1a42680ff (2026-08-16).
Data as JSON: /api/errors/982a3b34b2fc3912.
Report an issue: GitHub.