pypa/pip · error · SyntaxError

unterminated extra: %s

Error message

unterminated extra: %s

What it means

Raised by distlib's `parse_requirement` when a requirement includes an extras section (`name[...]`) whose opening `[` has no matching `]` before end of input. The parser scans for `]` via `remaining.find(']', 1)` and if not found raises `SyntaxError: unterminated extra`.

Source

Thrown at src/pip/_vendor/distlib/util.py:161

def parse_requirement(req):
    """
    Parse a requirement passed in as a string. Return a Container
    whose attributes contain the various parts of the requirement.
    """
    remaining = req.strip()
    if not remaining or remaining.startswith('#'):
        return None
    m = IDENTIFIER.match(remaining)
    if not m:
        raise SyntaxError('name expected: %s' % remaining)
    distname = m.groups()[0]
    remaining = remaining[m.end():]
    extras = mark_expr = versions = uri = None
    if remaining and remaining[0] == '[':
        i = remaining.find(']', 1)
        if i < 0:
            raise SyntaxError('unterminated extra: %s' % remaining)
        s = remaining[1:i]
        remaining = remaining[i + 1:].lstrip()
        extras = []
        while s:
            m = IDENTIFIER.match(s)
            if not m:
                raise SyntaxError('malformed extra: %s' % s)
            extras.append(m.groups()[0])
            s = s[m.end():]
            if not s:
                break
            if s[0] != ',':
                raise SyntaxError('comma expected in extras: %s' % s)
            s = s[1:].lstrip()
        if not extras:
            extras = None
    if remaining:
        if remaining[0] == '@':

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Close the extras bracket: `pkg[extra1,extra2]`.
  2. Quote the requirement in the shell to prevent `]` from being interpreted/stripped.
  3. Validate with `packaging.requirements.Requirement(...)` before use.

Example fix

# before
requests[security

# after
requests[security]
Defensive patterns

Strategy: validation

Validate before calling

from packaging.requirements import Requirement, InvalidRequirement

def validate_requirement_extras(line: str) -> None:
    try:
        Requirement(line)
    except InvalidRequirement as e:
        raise ValueError(f"Bad requirement: {e}") from e

Type guard

def extras_bracket_closed(line: str) -> bool:
    if "[" not in line:
        return True
    return line.count("[") == line.count("]")

Try / catch

null

Prevention

When it happens

Trigger: Parsing a requirement like `requests[security` (no closing bracket) with `parse_requirement`. Triggered when pip parses a requirement whose extras list is not closed.

Common situations: Typing `pkg[extra1,extra2` and forgetting the `]`; shell/quote stripping the `]`; copy-paste truncation; requirements files edited by hand.

Related errors


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