pypa/pip · error · InstallationError

Invalid requirement

Error message

Invalid requirement: {name!r}: {exc}

What it means

Raised by parse_req_from_editable (constructors.py:242) when the project-name portion extracted from an editable requirement string is not a valid PEP 508 requirement name (get_requirement raises InvalidRequirement). The original exception is wrapped as InstallationError with 'Invalid requirement: <name!r>: <exc>'.

Solutions

  1. Correct the project name to a valid PEP 508 name (letters, digits, _, -, .).
  2. Use the exact distribution name from the package's metadata.
  3. Re-run pip install -e '<name> @ <url>' with the corrected name.

Example fix

# before
pip install -e 'git+https://github.com/u/repo.git#egg=My Pkg'
# after
pip install -e 'my-pkg @ git+https://github.com/u/repo.git'
Defensive patterns

Strategy: validation

Validate before calling

from pip._vendor.packaging.requirements import Requirement, InvalidRequirement
import re

def editable_name_is_valid(line: str) -> bool:
    # Extract name from PEP 508 form or #egg=...
    m = re.match(r'^\s*([^@\s]+)\s*@', line)
    name = m.group(1) if m else None
    if name is None and '#egg=' in line:
        name = line.split('#egg=', 1)[1].split('&')[0].split(';')[0]
    if not name:
        return False
    try:
        Requirement(name)
        return True
    except InvalidRequirement:
        return False

Type guard

from pip._vendor.packaging.requirements import Requirement, InvalidRequirement

def is_valid_project_name(name: str) -> bool:
    try:
        Requirement(name)
        return True
    except InvalidRequirement:
        return False

Try / catch

from subprocess import run, CalledProcessError
try:
    run(["pip", "install", "-e", target], check=True)
except CalledProcessError:
    # Correct the name to a valid PEP 508 identifier and retry.
    run(["pip", "install", "-e", f"{clean_name} @ {url}"], check=True)

Prevention

When it happens

Trigger: The name parsed out of an editable spec (either the PEP 508 name part or the #egg= fragment) contains illegal characters or syntax — e.g. a name with spaces, dots-as-separators misuse, or invalid characters like '@' inside the name portion.

Common situations: Typos in the egg fragment ('#egg=My Pkg'); using a name that violates PEP 508; a URL accidentally parsed as the name portion.

Related errors


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

Appendix: source

Thrown at src/pip/_internal/req/constructors.py:242

    return msg


@dataclass(frozen=True)
class RequirementParts:
    requirement: Requirement | None
    link: Link | None
    markers: Marker | None
    extras: set[str]


def parse_req_from_editable(editable_req: str) -> RequirementParts:
    name, url, extras_override = parse_editable(editable_req)

    if name is not None:
        try:
            req: Requirement | None = get_requirement(name)
        except InvalidRequirement as exc:
            raise InstallationError(f"Invalid requirement: {name!r}: {exc}")
    else:
        req = None

    link = Link(url)

    return RequirementParts(req, link, None, extras_override)


# ---- The actual constructors follow ----


def install_req_from_editable(
    editable_req: str,
    comes_from: InstallRequirement | str | None = None,
    *,
    isolated: bool = False,
    hash_options: dict[str, list[str]] | None = None,
    constraint: bool = False,

View on GitHub (pinned to f399c37189)