{"id":"d45312f6908f5329","repo":"pypa/pip","slug":"pre-must-be-a-tuple-of-a-b-rc-non-negative","errorCode":null,"errorMessage":"pre must be a tuple of ('a'|'b'|'rc', non-negative int), got {value}","messagePattern":"pre must be a tuple of \\('a'\\|'b'\\|'rc', non-negative int\\), got (.+?)","errorType":"validation","errorClass":"InvalidVersion","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/version.py","lineNumber":296,"sourceCode":"        and len(release) > 0\n        and all(isinstance(i, int) and i >= 0 for i in release)\n    ):\n        return release\n    msg = f\"release must be a non-empty tuple of non-negative integers, got {release}\"\n    raise InvalidVersion(msg)\n\n\ndef _validate_pre(value: object, /) -> tuple[Literal[\"a\", \"b\", \"rc\"], int] | None:\n    if value is None:\n        return value\n    if isinstance(value, tuple) and len(value) == 2:\n        letter, number = value\n        letter = normalize_pre(letter)\n        if letter in {\"a\", \"b\", \"rc\"} and isinstance(number, int) and number >= 0:\n            # type checkers can't infer the Literal type here on letter\n            return (letter, number)  # type: ignore[return-value]\n    msg = f\"pre must be a tuple of ('a'|'b'|'rc', non-negative int), got {value}\"\n    raise InvalidVersion(msg)\n\n\ndef _validate_post(value: object, /) -> tuple[Literal[\"post\"], int] | None:\n    if value is None:\n        return value\n    if isinstance(value, int) and value >= 0:\n        return (\"post\", value)\n    msg = f\"post must be non-negative integer, got {value}\"\n    raise InvalidVersion(msg)\n\n\ndef _validate_dev(value: object, /) -> tuple[Literal[\"dev\"], int] | None:\n    if value is None:\n        return value\n    if isinstance(value, int) and value >= 0:\n        return (\"dev\", value)\n    msg = f\"dev must be non-negative integer, got {value}\"\n    raise InvalidVersion(msg)","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/version.py#L278-L314","documentation":"Raised by `_validate_pre(value)` when the `pre` argument to `Version.from_parts`/`__replace__` is not `None` and not a 2-tuple `(letter, number)` where `letter` normalizes to one of `a`/`b`/`rc` and `number` is a non-negative int. `None` is allowed (no pre-release). The letter is run through `normalize_pre`, so `alpha`/`a`/`A` all map to `a`, `beta`/`b` to `b`, `c`/`rc`/`pre`/`preview` to `rc`. Any other letter, wrong arity, or non-int/negative number is rejected.","triggerScenarios":"`Version.from_parts(release=(1,0), pre=('gamma', 1))`, `pre=('a',)`, `pre=('a', -1)`, `pre=('a', 1.5)`, `pre=('a', '1')`. The validator checks `isinstance(value, tuple) and len==2` then letter/number.","commonSituations":"Passing a string pre-release like `'a1'` instead of a tuple; wrong letter (`'alpha'` is fine but `'rc2'` as letter isn't); floats or strings for the number.","solutions":["Pass a 2-tuple: `pre=('a', 1)` (or `('rc', 2)`, `('b', 3)`).","Use an accepted letter spelling: `'a'`/`'alpha'`, `'b'`/`'beta'`, `'rc'`/`'c'`/`'pre'`/`'preview'`.","Ensure the number is a non-negative `int`.","For string input, prefer `Version('1.0a1')`."],"exampleFix":"// before\nVersion.from_parts(release=(1, 0), pre='a1')  # str -> raises\n\n// after\nVersion.from_parts(release=(1, 0), pre=('a', 1))\n# or\nVersion('1.0a1')","handlingStrategy":"type-guard","validationCode":"from pip._vendor.packaging.version import normalize_pre\n\ndef is_valid_pre(value: object) -> bool:\n    if value is None:\n        return True\n    if not (isinstance(value, tuple) and len(value) == 2):\n        return False\n    letter, number = value\n    try:\n        return normalize_pre(letter) in {'a', 'b', 'rc'} and isinstance(number, int) and not isinstance(number, bool) and number >= 0\n    except Exception:\n        return False","typeGuard":"from pip._vendor.packaging.version import normalize_pre\n\ndef is_pre_tuple(value: object) -> bool:\n    if value is None:\n        return True\n    if not (isinstance(value, tuple) and len(value) == 2):\n        return False\n    letter, number = value\n    try:\n        return (normalize_pre(letter) in {'a', 'b', 'rc'}\n                and isinstance(number, int) and not isinstance(number, bool) and number >= 0)\n    except Exception:\n        return False","tryCatchPattern":"from pip._vendor.packaging.version import Version, InvalidVersion\n\ntry:\n    v = Version.from_parts(release=release, pre=pre)\nexcept InvalidVersion as e:\n    if 'pre' in str(e):\n        pre = None  # or normalize from a string via Version(...)\n        v = Version.from_parts(release=release, pre=pre)\n    raise","preventionTips":["Pass `pre` as a 2-tuple `('a'|'b'|'rc', non_negative_int)` or `None`.","For string input, build via `Version('1.0a1')` instead of `from_parts`.","Use accepted letter spellings (`a`/`alpha`, `b`/`beta`, `rc`/`c`/`pre`/`preview`)."],"tags":["python","packaging","version","pep440","validation","from-parts","pre-release"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}