pypa/pip · error · RequirementsFileParseError

Invalid requirement: {line}\n{e.msg}

Error message

Invalid requirement: {line}\n{e.msg}

What it means

RequirementsFileParseError raised while parsing a single line of a requirements/constraints file: the line could not be split into args + options by pip's optparse-based line parser (OptionParsingError). The offending line is echoed along with the parser's message so the user can locate the typo.

Source

Thrown at src/pip/_internal/req/req_file.py:415

                    req_path, nested_constraint, [new_parsed_files, *parsed_files_stack]
                )
            else:
                yield line

    def _parse_file(
        self, filename: str, constraint: bool
    ) -> Generator[ParsedLine, None, None]:
        _, content = get_file_content(filename, self._session, constraint=constraint)

        lines_enum = preprocess(content)

        for line_number, line in lines_enum:
            try:
                args_str, opts = self._line_parser(line)
            except OptionParsingError as e:
                # add offending line
                msg = f"Invalid requirement: {line}\n{e.msg}"
                raise RequirementsFileParseError(msg)

            yield ParsedLine(
                filename,
                line_number,
                args_str,
                opts,
                constraint,
            )


def get_line_parser(finder: PackageFinder | None) -> LineParser:
    def parse_line(line: str) -> tuple[str, Values]:
        # Build new parser for each line since it accumulates appendable
        # options.
        parser = build_parser()
        defaults = parser.get_default_values()
        defaults.index_url = None
        if finder:

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Read {line} and {e.msg} from the error: they pinpoint the bad line and the parser complaint.
  2. Cross-check the option name against pip's supported requirement-line options (--index-url, --extra-index-url, --find-links, --hash, etc.).
  3. Quote values that contain spaces and ensure each '--opt=value' or '--opt value' pair is complete.
  4. Remove the offending option or move it to the CLI invocation if it isn't valid in a requirements file.

Example fix

# before — requirements.txt
requests --find-lins https://example.com

# after
requests --find-links https://example.com
Defensive patterns

Strategy: validation

Validate before calling

from pip._internal.req.req_file import get_line_parser, OptionParsingError
def validate_line(line: str, finder=None) -> bool:
    try:
        get_line_parser(finder)(line)
        return True
    except OptionParsingError as e:
        print(f'bad line: {line!r} -> {e.msg}')
        return False

Type guard

def is_valid_requirement_line(line: str) -> bool:
    return validate_line(line)

Try / catch

from pip._internal.req.req_file import get_line_parser, OptionParsingError
for line in open('requirements.txt'):
    line = line.strip()
    if not line or line.startswith('#'):
        continue
    try:
        get_line_parser(None)(line)
    except OptionParsingError as e:
        print(f'fix line: {line} ({e.msg})'); raise SystemExit(1)

Prevention

When it happens

Trigger: Running 'pip install -r requirements.txt' where a line uses an unknown option flag (e.g. '--foo'), a malformed option (missing value after '--index-url'), or text that optparse rejects. Anything in the options portion after the first '--'-prefixed token gets parsed by optparse.

Common situations: Typos in option names ('--find-links' misspelled); copy-pasting a shell-style '--index-url=http://...' that optparse still accepts but a missing '=' elsewhere breaks; environment-specific options from a teammate's machine; trailing option tokens a user thought were part of the package name.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/158de07c441fa226.json. Report an issue: GitHub.