pypa/pip · error · InstallationError

Unnamed requirements are not allowed as constraints

Error message

Unnamed requirements are not allowed as constraints

What it means

check_invalid_constraint_type (req_install.py:811-812) and collect_root_requirements (factory.py:551-553) reject constraint entries that have no package name (Unnamed requirements). Constraints must be a package name plus an optional version specifier; bare URLs or paths without a name are not allowed because the new resolver cannot key them.

Solutions

  1. Give the constraint a name using PEP 508 direct reference form: name @ url.
  2. Move unnamed path/url requirements out of the constraints file into the main requirements file.
  3. Express the constraint as pkg==<version> only.

Example fix

# before (constraints.txt)
git+https://github.com/org/pkg.git
# after
pkg @ git+https://github.com/org/pkg.git
Defensive patterns

Strategy: validation

Validate before calling

# Validate a constraints file has no unnamed requirements.
import sys
for line in open("constraints.txt"):
    s = line.strip()
    if not s or s.startswith("#"):
        continue
    # unnamed if it starts with a path/url indicator and has no 'name @'
    if (s.startswith(("http", "git+", "hg+", "svn+", "./", "/", ".."))) and "@" not in s.split()[0]:
        print(f"Unnamed constraint not allowed: {s}")

Prevention

When it happens

Trigger: A constraints file (-c constraints.txt) contains an unnamed requirement such as a bare URL or a local path without a name.

Common situations: Putting a bare URL or ./local/pkg directly in a constraints file instead of the requirements file.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/7d4f7b6c5e466aad. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/resolution/resolvelib/factory.py:553

            else:
                # require the base from the link
                yield self.make_requirement_from_candidate(cand)
                if ireq.extras:
                    # require the extras on top of the base candidate
                    yield self.make_requirement_from_candidate(
                        self._make_extras_candidate(cand, frozenset(ireq.extras))
                    )

    def collect_root_requirements(
        self, root_ireqs: list[InstallRequirement]
    ) -> CollectedRootRequirements:
        collected = CollectedRootRequirements([], {}, {})
        for i, ireq in enumerate(root_ireqs):
            if ireq.constraint:
                # Ensure we only accept valid constraints
                problem = check_invalid_constraint_type(ireq)
                if problem:
                    raise InstallationError(problem)
                if not ireq.match_markers():
                    continue
                assert ireq.name, "Constraint must be named"
                name = canonicalize_name(ireq.name)
                if name in collected.constraints:
                    collected.constraints[name] &= ireq
                else:
                    collected.constraints[name] = Constraint.from_ireq(ireq)
            else:
                reqs = list(
                    self._make_requirements_from_install_req(
                        ireq,
                        requested_extras=(),
                    )
                )
                if not reqs:
                    continue
                template = reqs[0]

View on GitHub (pinned to f399c37189)