pypa/pip · error · SyntaxError
unexpected trailing data
Error message
unexpected trailing data: %s
What it means
Raised as SyntaxError inside parse_requirement when, after successfully parsing the name, version, extras, URL, and any environment marker, there is still leftover data that does not start with '#' (a comment). The PEP 508 grammar allows an optional trailing comment but nothing else; any other residue is rejected as malformed. This guards against requirement strings with duplicate or appended junk after a complete, valid spec.
Solutions
- Strip or split the line so only one requirement remains; trailing comments must start with '#'.
- Run a pre-pass that normalizes whitespace and removes anything after the first '#' before parsing.
- Use packaging's Requirement parser to localize where the surplus data begins.
Example fix
// before
parse_requirement('pkg==1.0 ; python_version<"3" ; extra')
// after
parse_requirement('pkg==1.0 ; python_version<"3" # note') Defensive patterns
Strategy: validation
Validate before calling
def strip_requirement_line(line):
line = line.split('#', 1)[0].strip() # drop comment + surrounding ws
return line Type guard
null
Try / catch
try:
parse_requirement(line)
except SyntaxError as e:
if 'unexpected trailing data' in str(e):
line = line.split(';', 1)[0].strip()
parse_requirement(line) Prevention
- Split requirement lines on '#' before parsing.
- Ensure one requirement per line when reading from files.
When it happens
Trigger: parse_requirement('pkg>=1.0; python_version<"3" garbage'), parse_requirement('pkg==1.0 ;; marker'), or any string where a second ';' or extra token survives marker parsing. Also triggered by trailing characters after a valid marker expression that are not a '#' comment.
Common situations: Reading requirement lines from a file where multiple requirements got concatenated; requirements with double semicolons or stray punctuation after the marker; pasting specs that include inline annotations outside a comment.
Related errors
- invalid requirement
- Invalid requirement
- Invalid requirement
- Expected end of dependency specifier
- Expected end of marker expression
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/81e002a4b500b8e8.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/distlib/util.py:259
else:
m = VERSION_IDENTIFIER.match(s)
if not m:
raise SyntaxError('invalid constraint: %s' % s)
v = m.groups()[0]
s = s[m.end():].lstrip()
if s:
raise SyntaxError('invalid constraint: %s' % s)
versions = [('~=', v)]
if remaining:
if remaining[0] != ';':
raise SyntaxError('invalid requirement: %s' % remaining)
remaining = remaining[1:].lstrip()
mark_expr, remaining = parse_marker(remaining)
if remaining and remaining[0] != '#':
raise SyntaxError('unexpected trailing data: %s' % remaining)
if not versions:
rs = distname
else:
rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions]))
return Container(name=distname, extras=extras, constraints=versions, marker=mark_expr, url=uri, requirement=rs)
def get_resources_dests(resources_root, rules):
"""Find destinations for resources files"""
def get_rel_path(root, path):
# normalizes and returns a lstripped-/-separated path
root = root.replace(os.path.sep, '/')
path = path.replace(os.path.sep, '/')
assert path.startswith(root)
return path[len(root):].lstrip('/')
View on GitHub (pinned to f399c37189)