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
- Close the extras bracket: `pkg[extra1,extra2]`.
- Quote the requirement in the shell to prevent `]` from being interpreted/stripped.
- 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
- Close every `[` in an extras list with `]`.
- Shell-quote requirements to prevent `]` stripping.
- Lint requirements files for balanced brackets.
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
- malformed extra: %s
- comma expected in extras: %s
- error in string literal: %s
- unterminated string: %s
- unterminated parenthesis: %s
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/7318f0a22c7079ea.json.
Report an issue: GitHub.