{"id":"15d6eef383c09b66","repo":"pypa/pip","slug":"invalid-specifier-spec-r","errorCode":null,"errorMessage":"Invalid specifier: {spec!r}","messagePattern":"Invalid specifier: (.+?)","errorType":"validation","errorClass":"InvalidSpecifier","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/specifiers.py","lineNumber":587,"sourceCode":"        \">\": \"greater_than\",\n        \"===\": \"arbitrary\",\n    }\n\n    def __init__(self, spec: str = \"\", prereleases: bool | None = None) -> None:\n        \"\"\"Initialize a Specifier instance.\n\n        :param spec:\n            The string representation of a specifier which will be parsed and\n            normalized before use.\n        :param prereleases:\n            This tells the specifier if it should accept prerelease versions if\n            applicable or not. The default of ``None`` will autodetect it from the\n            given specifiers.\n        :raises InvalidSpecifier:\n            If the given specifier is invalid (i.e. bad syntax).\n        \"\"\"\n        if not self._regex.fullmatch(spec):\n            raise InvalidSpecifier(f\"Invalid specifier: {spec!r}\")\n\n        spec = spec.strip()\n        if spec.startswith(\"===\"):\n            operator, version = spec[:3], spec[3:].strip()\n        elif spec.startswith((\"~=\", \"==\", \"!=\", \"<=\", \">=\")):\n            operator, version = spec[:2], spec[2:].strip()\n        else:\n            operator, version = spec[:1], spec[1:].strip()\n\n        self._spec: tuple[str, str] = (operator, version)\n\n        # Store whether or not this Specifier should accept prereleases\n        self._prereleases = prereleases\n\n        # Specifier version cache\n        self._spec_version: tuple[str, Version] | None = None\n\n        # Populated on first wildcard (==X.*) comparison","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/specifiers.py#L569-L605","documentation":"Raised as InvalidSpecifier (specifiers.py:587), a ValueError subclass, by Specifier.__init__ when the input string does not fully match the operator+version regex (_regex.fullmatch). It is the primary PEP 440 specifier-syntax error, thrown before any operator/version splitting happens.","triggerScenarios":"Specifier('==>1.0'), Specifier('1.0'), Specifier('==1.0 beta'), Specifier('~>1.0'), Specifier(''), or any specifier missing a recognized operator (== != <= >= < > ~= ===). Also reached transitively when SpecifierSet('bad spec') parses each comma-separated piece.","commonSituations":"User-typed requirement strings from a config file or CLI. Tools forwarding npm-style ('^1.0') or gem-style ('~>1.0') specifiers into packaging. A trailing space, unicode lookalike operator, or missing operator.","solutions":["Rewrite the specifier using a PEP 440 operator: ==, !=, <=, >=, <, >, ~=, or ===.","Strip whitespace/unicode and ensure the version segment is a valid PEP 440 version (or arbitrary string after ===).","If accepting user input, validate with Specifier() inside a try/except InvalidSpecifier and report a friendly message."],"exampleFix":"# before\nfrom pip._vendor.packaging.specifiers import Specifier\nSpecifier(\"^1.2.3\")   # npm-style, not PEP 440\nSpecifier(\"==1.0 beta\")\n\n# after\nSpecifier(\">=1.2.3\")\nSpecifier(\"==1.0\")","handlingStrategy":"try-catch","validationCode":"from pip._vendor.packaging.specifiers import Specifier, InvalidSpecifier\ndef is_valid_specifier(s):\n    try:\n        Specifier(s)\n        return True\n    except InvalidSpecifier:\n        return False","typeGuard":"null","tryCatchPattern":"from pip._vendor.packaging.specifiers import InvalidSpecifier\ntry:\n    spec = Specifier(user_input)\nexcept InvalidSpecifier as e:\n    report_to_user(f'Not a valid PEP 440 specifier: {e}')","preventionTips":["Always wrap user-supplied specifier strings in try/except InvalidSpecifier.","Reject npm/gem-style operators (^, ~>, ->) at the input boundary."],"tags":["packaging","specifiers","validation","pep440"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}