pypa/pip · error · InstallationError

Invalid requirement

Error message

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

What it means

The general-purpose requirement string parser (_parse_req_string inside parse_req_from_line) could not build a Requirement object from the resolved requirement string. This is the most common 'Invalid requirement' error, enhanced with contextual hints: it detects when the string looks like a path or uses '=' instead of '=='.

Solutions

  1. Use '==' for exact version pins: 'foo==1.0' not 'foo=1.0'
  2. Read the Hint in the error message — it specifically detects path-like strings and single-equals mistakes
  3. Validate the string with packaging.requirements.Requirement() in a REPL to get a precise error
  4. Check for invisible characters or encoding issues in requirements files

Example fix

# before
pip install requests=2.28.0

# after
pip install requests==2.28.0
Defensive patterns

Strategy: validation

Validate before calling

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

def validate_requirement_string(req_str: str) -> bool:
    try:
        Requirement(req_str)
        return True
    except InvalidRequirement:
        return False

for line in requirements_lines:
    if not validate_requirement_string(line):
        print(f"Invalid requirement: {line!r}")

Type guard

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

def is_valid_requirement(req_str: str) -> bool:
    """Type guard: True if req_str parses as a valid PEP 508 requirement."""
    try:
        Requirement(req_str)
        return True
    except InvalidRequirement:
        return False

Try / catch

from pip._internal.exceptions import InstallationError

try:
    parts = parse_req_from_line(name, line_source)
except InstallationError as e:
    msg = str(e)
    if "Did you mean ==" in msg:
        # auto-fix single-equals
        fixed = name.replace("=", "==", 1)
        parts = parse_req_from_line(fixed, line_source)
    else:
        raise

Prevention

When it happens

Trigger: Running 'pip install foo=1.0' (single equals). Passing a bare path that doesn't resolve to an installable. Any PEP 508 syntax error in a requirement string from the command line or a requirements file line.

Common situations: Using '=' instead of '==' for version pinning. Misspelled package names. Requirement strings with stray characters. Requirements files with lines that were corrupted by environment variable expansion or line-joining.

Related errors


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

Appendix: source

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

        return f"{text} (from {line_source})"

    def _parse_req_string(req_as_string: str) -> Requirement:
        try:
            return get_requirement(req_as_string)
        except InvalidRequirement as exc:
            if os.path.sep in req_as_string:
                add_msg = "It looks like a path."
                add_msg += deduce_helpful_msg(req_as_string)
            elif "=" in req_as_string and not any(
                op in req_as_string for op in operators
            ):
                add_msg = "= is not a valid operator. Did you mean == ?"
            else:
                add_msg = ""
            msg = with_source(f"Invalid requirement: {req_as_string!r}: {exc}")
            if add_msg:
                msg += f"\nHint: {add_msg}"
            raise InstallationError(msg)

    if req_as_string is not None:
        req: Requirement | None = _parse_req_string(req_as_string)
    else:
        req = None

    return RequirementParts(req, link, markers, extras)


def install_req_from_line(
    name: str,
    comes_from: str | InstallRequirement | None = None,
    *,
    isolated: bool = False,
    hash_options: dict[str, list[str]] | None = None,
    constraint: bool = False,
    line_source: str | None = None,
    user_supplied: bool = False,

View on GitHub (pinned to f399c37189)