{"record":{"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":369,"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        # Version range cache (populated by _to_ranges)","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/specifiers.py#L351-L387","documentation":"Raised as InvalidSpecifier (a ValueError subclass) by Specifier.__init__ at specifiers.py:368 when the spec string fails a fullmatch against the PEP 440 specifier regex (_specifier_regex). The regex requires a recognized operator (~=, ==, !=, <=, >=, <, >, ===) followed by a version-like token; any string that does not match is rejected before any parsing happens. This is the primary entry-point validation for every Specifier and SpecifierSet.","triggerScenarios":"Specifier('lolwat'); Specifier('>>1.0'); Specifier('=1.0'); Specifier('=='); Specifier('>= 1.0.0!'); passing a specifier with an unknown operator, no version, or stray characters. Also fires indirectly when SpecifierSet('bad spec') parses each comma-delimited token.","commonSituations":"Reading requirements from a hand-edited requirements.txt/extra_requires with a typo; user-supplied version constraint strings from a config file or CLI; a dependency-pinning tool that concatenates operator and version incorrectly (e.g. '>=' + '' when version is blank); copy-paste of npm-style '^1.0' or cargo-style specifiers into a Python project.","solutions":["Inspect the exact spec string in the error message ({spec!r}) and correct the operator/version syntax to PEP 440 (~=, ==, !=, <=, >=, <, >, ===).","If the value is user/config supplied, wrap construction in try/except InvalidSpecifier and report a clear validation error back to the user.","Strip whitespace and verify the string starts with a known operator before constructing, or pre-validate with packaging.specifiers.Specifier only after a sanity regex.","For empty/optional constraints, pass an empty string to SpecifierSet('') rather than constructing a Specifier with a blank version."],"exampleFix":"# before\nfrom packaging.specifiers import Specifier\nspec = Specifier('^1.2.3')  # InvalidSpecifier: Invalid specifier: '^1.2.3'\n\n# after\nfrom packaging.specifiers import Specifier, InvalidSpecifier\ntry:\n    spec = Specifier('>=1.2.3')\nexcept InvalidSpecifier:\n    spec = Specifier('>=1.0.0')","handlingStrategy":"validation","validationCode":"from packaging.specifiers import Specifier, InvalidSpecifier\n\ndef safe_specifier(s: str):\n    try:\n        return Specifier(s)\n    except InvalidSpecifier as e:\n        raise ValueError(f'Bad PEP 440 specifier {s!r}: {e}') from e","typeGuard":null,"tryCatchPattern":"from packaging.specifiers import InvalidSpecifier\ntry:\n    spec = Specifier(user_input)\nexcept InvalidSpecifier:\n    spec = None  # or a safe default","preventionTips":["Always build specifier strings from a known operator constant + a validated version, never by concatenating raw user input.","Pre-validate requirement strings with the packaging.specifiers regex or by constructing SpecifierSet early so errors surface at the boundary.","Treat empty/optional version fields as empty SpecifierSet('') rather than feeding blank versions into Specifier."],"tags":["packaging","validation","specifiers","pep440"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}