pypa/pip · error · ParserSyntaxError
Expected end of dependency specifier
Error message
Expected end of dependency specifier
What it means
Raised by parse_requirement()/Requirement() as an InvalidRequirement (originating from a ParserSyntaxError) when tokenizer.expect("END", ...) at line 126 fails: after parsing the name, extras, and requirement details, there is leftover input the grammar cannot consume. The parser expected end-of-input but found an unexpected token.
Solutions
- Print repr() of the offending requirement string to spot trailing whitespace or stray characters.
- Split compound lines on valid separators and parse each requirement individually.
- Strip the string and validate it parses with packaging.requirements.Requirement() in a test before committing it.
Example fix
// before
Requirement('requests >= 2.0 ;')
// after
Requirement('requests >= 2.0') Defensive patterns
Strategy: validation
Validate before calling
from packaging.requirements import Requirement, InvalidRequirement
def valid_requirement(s):
try:
Requirement(s)
return True
except InvalidRequirement:
return False Try / catch
from packaging.requirements import Requirement, InvalidRequirement
try:
req = Requirement(raw)
except InvalidRequirement as e:
raise ValueError(f'bad requirement {raw!r}: {e}') from e Prevention
- Always construct requirement strings programmatically and round-trip them through Requirement(...).str() to normalize.
- Trim stray characters and avoid concatenating fragments that may leave trailing tokens.
When it happens
Trigger: A requirement string with trailing garbage after a valid specifier/marker, e.g. 'pkg >= 1.0 extra_token', 'pkg; python_version >= "3.0" )', or two specifier sets without a separator. The recursive descent parser finishes the recognized grammar but the tokenizer is not at END.
Common situations: Manually constructed or templated requirement strings with a stray character; concatenating fragments ('pkg>=1.0' + ' ' + stray); requirements.txt lines with invisible/unexpected characters; copy-paste introducing a trailing punctuation.
Related errors
- Expected extra name after comma
- Expected URL after @
- Expected end of marker expression
- Expected whitespace after 'not'
- Expected whitespace after URL
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/ae603c8e2bfee7e8.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/_parser.py:126
def _parse_requirement(tokenizer: Tokenizer) -> ParsedRequirement:
"""
requirement = WS? IDENTIFIER WS? extras WS? requirement_details
"""
tokenizer.consume("WS")
name_token = tokenizer.expect(
"IDENTIFIER", expected="package name at the start of dependency specifier"
)
name = name_token.text
tokenizer.consume("WS")
extras = _parse_extras(tokenizer)
tokenizer.consume("WS")
url, specifier, marker = _parse_requirement_details(tokenizer)
tokenizer.expect("END", expected="end of dependency specifier")
return ParsedRequirement(name, url, extras, specifier, marker)
def _parse_requirement_details(
tokenizer: Tokenizer,
) -> tuple[str, str, MarkerList | None]:
"""
requirement_details = AT URL (WS requirement_marker?)?
| specifier WS? (requirement_marker)?
"""
specifier = ""
url = ""
marker = None
if tokenizer.check("AT"):
tokenizer.read()View on GitHub (pinned to f399c37189)