pypa/pip · error · InvalidVersion
pre must be a tuple of ('a'|'b'|'rc', non-negative int), got
Error message
pre must be a tuple of ('a'|'b'|'rc', non-negative int), got {value} What it means
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.
Source
Thrown at src/pip/_vendor/packaging/version.py:296
and len(release) > 0
and all(isinstance(i, int) and i >= 0 for i in release)
):
return release
msg = f"release must be a non-empty tuple of non-negative integers, got {release}"
raise InvalidVersion(msg)
def _validate_pre(value: object, /) -> tuple[Literal["a", "b", "rc"], int] | None:
if value is None:
return value
if isinstance(value, tuple) and len(value) == 2:
letter, number = value
letter = normalize_pre(letter)
if letter in {"a", "b", "rc"} and isinstance(number, int) and number >= 0:
# type checkers can't infer the Literal type here on letter
return (letter, number) # type: ignore[return-value]
msg = f"pre must be a tuple of ('a'|'b'|'rc', non-negative int), got {value}"
raise InvalidVersion(msg)
def _validate_post(value: object, /) -> tuple[Literal["post"], int] | None:
if value is None:
return value
if isinstance(value, int) and value >= 0:
return ("post", value)
msg = f"post must be non-negative integer, got {value}"
raise InvalidVersion(msg)
def _validate_dev(value: object, /) -> tuple[Literal["dev"], int] | None:
if value is None:
return value
if isinstance(value, int) and value >= 0:
return ("dev", value)
msg = f"dev must be non-negative integer, got {value}"
raise InvalidVersion(msg)View on GitHub (pinned to d7d0d0a394)
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')`.
Example fix
// before
Version.from_parts(release=(1, 0), pre='a1') # str -> raises
// after
Version.from_parts(release=(1, 0), pre=('a', 1))
# or
Version('1.0a1') Defensive patterns
Strategy: type-guard
Validate before calling
from pip._vendor.packaging.version import normalize_pre
def is_valid_pre(value: object) -> bool:
if value is None:
return True
if not (isinstance(value, tuple) and len(value) == 2):
return False
letter, number = value
try:
return normalize_pre(letter) in {'a', 'b', 'rc'} and isinstance(number, int) and not isinstance(number, bool) and number >= 0
except Exception:
return False Type guard
from pip._vendor.packaging.version import normalize_pre
def is_pre_tuple(value: object) -> bool:
if value is None:
return True
if not (isinstance(value, tuple) and len(value) == 2):
return False
letter, number = value
try:
return (normalize_pre(letter) in {'a', 'b', 'rc'}
and isinstance(number, int) and not isinstance(number, bool) and number >= 0)
except Exception:
return False Try / catch
from pip._vendor.packaging.version import Version, InvalidVersion
try:
v = Version.from_parts(release=release, pre=pre)
except InvalidVersion as e:
if 'pre' in str(e):
pre = None # or normalize from a string via Version(...)
v = Version.from_parts(release=release, pre=pre)
raise Prevention
- 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`).
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- epoch must be non-negative integer, got {epoch}
- release must be a non-empty tuple of non-negative integers,
- post must be non-negative integer, got {value}
- dev must be non-negative integer, got {value}
- local must be a valid version string, got {value!r}
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/d45312f6908f5329.json.
Report an issue: GitHub.