{"id":"7d4f7b6c5e466aad","repo":"pypa/pip","slug":"unnamed-requirements-are-not-allowed-as-constraint","errorCode":null,"errorMessage":"Unnamed requirements are not allowed as constraints","messagePattern":"Unnamed requirements are not allowed as constraints","errorType":"exception","errorClass":"InstallationError","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/resolution/resolvelib/factory.py","lineNumber":553,"sourceCode":"            else:\n                # require the base from the link\n                yield self.make_requirement_from_candidate(cand)\n                if ireq.extras:\n                    # require the extras on top of the base candidate\n                    yield self.make_requirement_from_candidate(\n                        self._make_extras_candidate(cand, frozenset(ireq.extras))\n                    )\n\n    def collect_root_requirements(\n        self, root_ireqs: list[InstallRequirement]\n    ) -> CollectedRootRequirements:\n        collected = CollectedRootRequirements([], {}, {})\n        for i, ireq in enumerate(root_ireqs):\n            if ireq.constraint:\n                # Ensure we only accept valid constraints\n                problem = check_invalid_constraint_type(ireq)\n                if problem:\n                    raise InstallationError(problem)\n                if not ireq.match_markers():\n                    continue\n                assert ireq.name, \"Constraint must be named\"\n                name = canonicalize_name(ireq.name)\n                if name in collected.constraints:\n                    collected.constraints[name] &= ireq\n                else:\n                    collected.constraints[name] = Constraint.from_ireq(ireq)\n            else:\n                reqs = list(\n                    self._make_requirements_from_install_req(\n                        ireq,\n                        requested_extras=(),\n                    )\n                )\n                if not reqs:\n                    continue\n                template = reqs[0]","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/resolution/resolvelib/factory.py#L535-L571","documentation":"InstallationError raised by check_invalid_constraint_type (called from collect_root_requirements) when a requirement marked as a constraint (-c file) has no name — e.g. a URL or a bare path. Constraints may only constrain a named project plus version specifier; an unnamed entry is meaningless as a constraint and the resolver rejects it. A deprecation warning precedes the failure.","triggerScenarios":"A constraints file (passed via '-c constraints.txt') contains a line like 'https://example.com/pkg.tar.gz' or a local path with no project name, and pip is resolving with the new resolver. check_invalid_constraint_type returns the problem string and collect_root_requirements raises InstallationError.","commonSituations":"Migrating an old constraints file that listed direct URL pins; mixing install requirements and constraint entries; tooling that writes constraints from a lockfile containing direct references.","solutions":["Open the constraints file and remove or rename any unnamed/URL/path lines.","Replace direct-URL constraints with a named specifier, e.g. 'package==1.2.3', and put the URL on the install side instead.","Move any URL requirement out of the '-c' file into a regular '-r' requirements file.","Re-run pip to confirm no unnamed constraint remains."],"exampleFix":"# before — constraints.txt\nhttps://example.com/packages/foo-1.0.tar.gz\n\n# after\nfoo==1.0","handlingStrategy":"validation","validationCode":"def constraints_have_no_unnamed(path: str) -> bool:\n    bad = []\n    for line in open(path):\n        s = line.strip()\n        if not s or s.startswith('#') or s.startswith('-'):\n            continue\n        if '://' in s or s.endswith(('.whl', '.tar.gz', '.zip')) or '/' in s and '=' not in s.split('/')[0]:\n            bad.append(s)\n    if bad:\n        print(f'unnamed constraints: {bad}')\n        return False\n    return True","typeGuard":"def is_named_constraint(line: str) -> bool:\n    s = line.strip()\n    if not s or s.startswith(('#', '-')):\n        return True\n    from pip._vendor.packaging.requirements import Requirement\n    try:\n        r = Requirement(s); return bool(r.name)\n    except Exception:\n        return False","tryCatchPattern":"if not constraints_have_no_unnamed('constraints.txt'):\n    print('fix unnamed constraints before pip')\nelse:\n    run_pip(['install', '-c', 'constraints.txt', 'pkg'])","preventionTips":["Keep constraints files to 'name==version' lines only.","Lint constraints files in pre-commit for URLs/paths.","Generate constraints from a trusted lockfile tool that emits named specs."],"tags":["constraints","resolver","config"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}