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
- Move editable installs to the main requirements file, not the constraints file.
- 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
- Put editable (-e) installs only in the main requirements file.
- Use plain version specifiers in constraints files.
- Lint constraints files for -e flags in CI.
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
- Constraints cannot have extras
- Could not detect requirement name for
- Could not open file
- Could not satisfy constraints for
- is not a valid editable requirement. It should either be a…
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)