{"record":{"id":"a4cfaf953be4d51e","repo":"nodejs/node","slug":"invalid-specifier-spec","errorCode":null,"errorMessage":"Invalid specifier: '{spec}'","messagePattern":"Invalid specifier: '(.+?)'","errorType":"validation","errorClass":"InvalidSpecifier","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/packaging/specifiers.py","lineNumber":245,"sourceCode":"        \"===\": \"arbitrary\",\n    }\n\n    def __init__(self, spec: str = \"\", prereleases: Optional[bool] = 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        match = self._regex.search(spec)\n        if not match:\n            raise InvalidSpecifier(f\"Invalid specifier: '{spec}'\")\n\n        self._spec: Tuple[str, str] = (\n            match.group(\"operator\").strip(),\n            match.group(\"version\").strip(),\n        )\n\n        # Store whether or not this Specifier should accept prereleases\n        self._prereleases = prereleases\n\n    # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515\n    @property  # type: ignore[override]\n    def prereleases(self) -> bool:\n        # If there is an explicit prereleases set for this, then we'll just\n        # blindly use that.\n        if self._prereleases is not None:\n            return self._prereleases\n\n        # Look at all of our specifiers and determine if they are inclusive","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/packaging/specifiers.py#L227-L263","documentation":"packaging.specifiers.InvalidSpecifier raised by Specifier.__init__ when the operator+version regex finds no match in the supplied spec string. The regex expects one of the PEP 440 operator prefixes (==, !=, <=, >=, <, >, ~=, ===) followed by a version-like token; anything else is rejected before any normalization.","triggerScenarios":"Constructing Specifier('1.0') (missing operator), Specifier('=>1.0') (wrong operator syntax), Specifier('==1.0,<2') (compound, which belongs to SpecifierSet not Specifier), or any spec with stray whitespace/punctuation that breaks the single-spec regex.","commonSituations":"Passing a requirements-style specifier directly to Specifier instead of SpecifierSet, typos in version constraints, or building specifiers from unvalidated user input / config files.","solutions":["Use SpecifierSet for multi-constraint strings like '>=1.0,<2.0'.","Ensure the spec starts with a valid PEP 440 operator (==, !=, <=, >=, <, >, ~=, ===).","Validate or sanitize user-supplied spec strings before constructing a Specifier, catching InvalidSpecifier to report the bad input."],"exampleFix":"# before\nspec = Specifier('>=1.0,<2.0')\n\n# after\nspec = SpecifierSet('>=1.0,<2.0')","handlingStrategy":"validation","validationCode":"import re\n_spec_re = re.compile(r'^(==|!=|<=|>=|<|>|~=|===)\\s*[^\\s,]+')\ndef is_valid_specifier(s: str) -> bool:\n    return bool(_spec_re.match(s.strip()))","typeGuard":"from packaging.specifiers import Specifier, InvalidSpecifier\ndef is_single_specifier(s: str) -> bool:\n    try:\n        Specifier(s)\n        return True\n    except InvalidSpecifier:\n        return False","tryCatchPattern":"try:\n    spec = Specifier(user_input)\nexcept InvalidSpecifier as e:\n    raise ValueError(f'Bad version constraint {user_input!r}: {e}') from e","preventionTips":["Use SpecifierSet for any string that may contain commas.","Validate specifier strings from user/config input at the boundary.","Reference PEP 440 operator syntax when documenting accepted input."],"tags":["packaging","specifiers","pep440","validation"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}