pypa/pip · error · InstallationError

Editable requirements are not allowed as constraints

Error message

Editable requirements are not allowed as constraints

What it means

check_invalid_constraint_type (req_install.py:813-814) and collect_root_requirements (factory.py:551-553) reject editable (-e) requirements inside a constraints file. Constraints only constrain versions; editable installs are a deployment form, not a version pin, so the new resolver forbids them in -c files.

Solutions

  1. Move editable installs to the main requirements file, not the constraints file.
  2. In the constraints file use a plain version specifier (pkg==X) for the same package.

Example fix

# before (constraints.txt)
-e ./local/pkg
# after
# in constraints.txt:
pkg==1.0
# in requirements.txt:
-e ./local/pkg
Defensive patterns

Strategy: validation

Validate before calling

# Validate a constraints file has no editable (-e) lines.
for line in open("constraints.txt"):
    s = line.strip()
    if s.startswith("-e") or s.startswith("--editable"):
        print(f"Editable requirement not allowed in constraints: {s}")

Prevention

When it happens

Trigger: A constraints file referenced via -c contains an editable requirement line such as `-e ./local/pkg` or `-e git+https://...`.

Common situations: Trying to pin a locally-developed editable package as a constraint; porting old-style constraints that mixed -e lines.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/4d9c74eb03576191. 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)