astral-sh/uv · error

Unnamed requirements are not allowed as exclusions (found: `

Error message

Unnamed requirements are not allowed as exclusions (found: `{requirement}`)

What it means

Exclusions (e.g., `--exclude` inputs merged in RequirementsSpecification) work by package name, so each parsed requirement must be named. When an exclusion source yields an UnresolvedRequirement::Unnamed (URL/path requirement), uv errors out during the excludes-merge loop, printing the offending requirement.

Source

Thrown at crates/uv-requirements/src/specification.rs:675

            spec.no_index |= source.no_index;
            spec.extra_index_urls.extend(source.extra_index_urls);
            spec.find_links.extend(source.find_links);
            spec.no_binary.extend(source.no_binary);
            spec.no_build.extend(source.no_build);
            spec.require_hashes |= source.require_hashes;
        }

        // Collect excludes.
        for source in excludes {
            let source = Self::from_source_with_cache(source, client_builder, &mut cache).await?;
            for req_spec in source.requirements {
                match req_spec.requirement {
                    UnresolvedRequirement::Named(requirement) => {
                        spec.excludes
                            .push(ExcludeDependency::Dependency(requirement.name));
                    }
                    UnresolvedRequirement::Unnamed(requirement) => {
                        return Err(anyhow::anyhow!(
                            "Unnamed requirements are not allowed as exclusions (found: `{requirement}`)"
                        ));
                    }
                }
            }
            spec.excludes.extend(source.excludes);
        }

        Ok(spec)
    }

    /// Parse an individual package requirement.
    pub fn parse_package(name: &str) -> Result<UnresolvedRequirementSpecification> {
        let requirement = RequirementsTxtRequirement::parse(name, &*CWD, false)
            .with_context(|| format!("Failed to parse: `{name}`"))?;
        Ok(UnresolvedRequirementSpecification::from(requirement))
    }

View on GitHub (pinned to f1a42680ff)

Solutions

  1. Replace the unnamed entry with the package's name only, e.g., `--exclude my-pkg`.
  2. If you meant to remove a URL requirement from the resolve, delete or edit that line in the requirements source instead of using --exclude.
  3. For VCS/URL deps, find their distribution name (from the wheel/sdist metadata) and exclude that name.

Example fix

# before
uv pip compile requirements.txt --exclude ./wheels/team-util-1.0-py3-none-any.whl
# after
uv pip compile requirements.txt --exclude team-util
Defensive patterns

Strategy: validation

Validate before calling

# Rust: only pass named requirements into the excludes pipeline
fn exclusion_names(reqs: &[RequirementEntry]) -> anyhow::Result<Vec<PackageName>> {
    reqs.iter()
        .map(|entry| match &entry.requirement {
            UnresolvedRequirement::Named(r) => Ok(r.name.clone()),
            UnresolvedRequirement::Unnamed(r) => {
                anyhow::bail!("exclusions must be named, got: {r}")
            }
        })
        .collect()
}

Type guard

fn is_excludable(entry: &RequirementEntry) -> bool {
    matches!(entry.requirement, UnresolvedRequirement::Named(_))
}

Prevention

When it happens

Trigger: Passing `--exclude https://github.com/org/repo` or `--exclude ./local/pkg.tar.gz` to a command that supports exclusions; feeding an exclusion file that lists a direct URL dependency instead of a package name.

Common situations: Assuming `--exclude` accepts the same syntax as requirements (URLs, paths, VCS specs); scripted dependency pruning that copies requirement lines verbatim into an exclusion list.

Related errors


AI-assisted analysis of astral-sh/uv@f1a42680ff (2026-08-16). Data as JSON: /api/errors/1c74f1d5b63380f5. Report an issue: GitHub.