astral-sh/uv · error
Unnamed requirements are not allowed as constraints (found:
Error message
Unnamed requirements are not allowed as constraints (found: `{requirement}`) What it means
Constraints in uv must be named requirements (e.g., `flask<2`), because a constraint only pins versions of an already-requested package. When a constraint source is parsed and an UnresolvedRequirement::Unnamed (a direct URL or file path requirement) is found, uv rejects it immediately during merging.
Source
Thrown at crates/uv-requirements/src/specification.rs:610
spec.no_binary.extend(source.no_binary);
spec.no_build.extend(source.no_build);
spec.require_hashes |= source.require_hashes;
}
// Read all constraints, treating both requirements _and_ constraints as constraints.
// Overrides are ignored.
for source in constraints {
let source = Self::from_source_with_cache(source, client_builder, &mut cache).await?;
for entry in source.requirements {
match entry.requirement {
UnresolvedRequirement::Named(requirement) => {
spec.constraints.push(NameRequirementSpecification {
requirement,
hashes: entry.hashes,
});
}
UnresolvedRequirement::Unnamed(requirement) => {
return Err(anyhow::anyhow!(
"Unnamed requirements are not allowed as constraints (found: `{requirement}`)"
));
}
}
}
spec.constraints.extend(source.constraints);
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())
{
return Err(anyhow::anyhow!(
"Multiple index URLs specified: `{existing}` vs. `{index_url}`",
));
}
spec.index_url = Some(index_url);
}View on GitHub (pinned to f1a42680ff)
Solutions
- Remove the unnamed (URL/path) entry named in the error from the constraints file — constraints cannot pin direct-URL packages.
- If the direct-URL package must be pinned, move it to the main requirements source (it is already fully specified there) and constrain only named packages in the constraints file.
- If you want the exact version of a local package, declare it in the requirements with its path and use constraints only for its transitive named dependencies.
Example fix
# before (constraints.txt) numpy==1.26.4 ./wheels/team-util-1.0-py3-none-any.whl # after (constraints.txt) numpy==1.26.4 # direct URL moved to requirements.txt instead
Defensive patterns
Strategy: validation
Validate before calling
# Rust: reject unnamed requirements before passing a file as constraints
use uv_requirements::UnresolvedRequirement;
fn validate_constraints(reqs: &[RequirementEntry]) -> anyhow::Result<()> {
for entry in reqs {
if let UnresolvedRequirement::Unnamed(ref r) = entry.requirement {
anyhow::bail!("unnamed requirement not allowed as constraint: {r}");
}
}
Ok(())
} Type guard
fn is_named_constraint(entry: &RequirementEntry) -> bool {
matches!(entry.requirement, UnresolvedRequirement::Named(_))
} Prevention
- Keep constraints files to `name<op>version` lines only — no URLs, paths, or VCS specs.
- Never reuse a full requirements.txt as a constraints file without pruning direct-URL entries.
- In CI, lint constraint files for lines that don't start with a package name.
When it happens
Trigger: Running `uv pip compile -c constraints.txt` (or `uv lock` with a constraints file) where constraints.txt contains a line like `./libs/my-pkg.tar.gz`, `https://example.com/pkg.whl`, or a VCS URL; passing a URL requirement via `--constraint` directly.
Common situations: Reusing a full requirements.txt as a constraints file without pruning its URL entries; CI that generates constraints from a lock export that includes direct-URL dependencies; teams copy-pasting a private-package URL into the constraints file.
Related errors
- Unnamed requirements are not allowed as exclusions (found: `
- pip-compile's `--emit-options` is unsupported (try `--emit-b
- Extra names must start and end with a letter or digit and ma
- The file `{}` appears to be a `pylock.toml` file, but constr
- The file `{}` appears to be a TOML file, but constraints mus
AI-assisted analysis of astral-sh/uv@f1a42680ff (2026-08-16).
Data as JSON: /api/errors/6d6afad73df231dd.
Report an issue: GitHub.