{"id":"99ed8217502d0423","repo":"pypa/pip","slug":"invalid-requirement-s","errorCode":null,"errorMessage":"invalid requirement: %s","messagePattern":"invalid requirement: (.+?)","errorType":"validation","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/distlib/util.py","lineNumber":253,"sourceCode":"                remaining = remaining[i + 1:].lstrip()\n                # As a special diversion from PEP 508, allow a version number\n                # a.b.c in parentheses as a synonym for ~= a.b.c (because this\n                # is allowed in earlier PEPs)\n                if COMPARE_OP.match(s):\n                    versions, _ = get_versions(s)\n                else:\n                    m = VERSION_IDENTIFIER.match(s)\n                    if not m:\n                        raise SyntaxError('invalid constraint: %s' % s)\n                    v = m.groups()[0]\n                    s = s[m.end():].lstrip()\n                    if s:\n                        raise SyntaxError('invalid constraint: %s' % s)\n                    versions = [('~=', v)]\n\n    if remaining:\n        if remaining[0] != ';':\n            raise SyntaxError('invalid requirement: %s' % remaining)\n        remaining = remaining[1:].lstrip()\n\n        mark_expr, remaining = parse_marker(remaining)\n\n    if remaining and remaining[0] != '#':\n        raise SyntaxError('unexpected trailing data: %s' % remaining)\n\n    if not versions:\n        rs = distname\n    else:\n        rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions]))\n    return Container(name=distname, extras=extras, constraints=versions, marker=mark_expr, url=uri, requirement=rs)\n\n\ndef get_resources_dests(resources_root, rules):\n    \"\"\"Find destinations for resources files\"\"\"\n\n    def get_rel_path(root, path):","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/distlib/util.py#L235-L271","documentation":"Raised by parse_requirement() when, after parsing the name, extras, and version/URL, there is leftover text whose first character is not ';' (the marker separator). This means the requirement has trailing content that is neither a valid URL, version clause, nor a marker, so it is rejected as an invalid requirement (SyntaxError).","triggerScenarios":"parse_requirement('pkg extra'), parse_requirement('pkg >= 1.0 garbage'), parse_requirement('pkg[extra] something'), or any requirement with unparseable trailing tokens that do not start with ';'.","commonSituations":"Typos in requirements.txt (e.g. a stray word), comments appended without a '#', or concatenation of a requirement with extra metadata without a separator.","solutions":["Remove the trailing junk shown after 'invalid requirement:'.","If the trailing text is an environment marker, prefix it with '; ': 'pkg >= 1.0 ; python_version >= \"3.8\"'.","If it is a comment, prefix it with '#'."],"exampleFix":"// before\nparse_requirement('requests >= 2.31.0 security')\n// after\nparse_requirement('requests >= 2.31.0')","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from distlib.util import parse_requirement\ntry:\n    spec = parse_requirement(raw)\nexcept SyntaxError as e:\n    if 'invalid requirement' in str(e):\n        # the whole string is malformed; surface to user / skip line\n        continue\n    raise","preventionTips":["Keep one requirement per line in requirements.txt.","Prefix environment markers with '; ' and comments with '#'.","Validate requirement files line-by-line in a try/except loop."],"tags":["requirement","parsing","pep508","packaging","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}