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() (version.py:285-300) when the pre-release value is not a 2-tuple whose first element normalizes (via normalize_pre) to 'a', 'b', or 'rc' and whose second element is a non-negative int. Valid spellings include 'alpha', 'a', 'beta', 'b', 'preview', 'pre', 'c', 'rc' for the letter. Passing None is allowed (means no pre-release).
Solutions
- Pass pre as a 2-tuple: ('a', 1), ('b', 2), ('rc', 1), or use accepted aliases like ('alpha', 1).
- Ensure the second element is a non-negative int.
- Pass None (or omit) if there is no pre-release segment.
Example fix
// before
Version.from_parts(release=(1, 0), pre='alpha1')
// after
Version.from_parts(release=(1, 0), pre=('alpha', 1)) Defensive patterns
Strategy: type-guard
Validate before calling
from packaging.version import Version, InvalidVersion, normalize_pre
def safe_from_parts(*, release, pre=None, **kwargs):
if pre is not None:
if not (isinstance(pre, tuple) and len(pre) == 2):
raise TypeError(f"pre must be a 2-tuple, got {pre!r}")
letter, number = pre
if normalize_pre(letter) not in {'a', 'b', 'rc'}:
raise ValueError(f"pre letter must normalize to a/b/rc, got {letter!r}")
if not isinstance(number, int) or number < 0:
raise TypeError(f"pre number must be non-negative int, got {number!r}")
return Version.from_parts(release=release, pre=pre, **kwargs) Type guard
from packaging.version import normalize_pre
def is_valid_pre(value) -> bool:
if value is None:
return True
return (
isinstance(value, tuple)
and len(value) == 2
and isinstance(value[0], str)
and normalize_pre(value[0]) in {'a', 'b', 'rc'}
and isinstance(value[1], int)
and value[1] >= 0
) Try / catch
from packaging.version import InvalidVersion
try:
v = Version.from_parts(release=(1,), pre=pre)
except InvalidVersion as e:
if "pre must be" in str(e):
logger.error("Invalid pre-release value: %s", pre)
raise Prevention
- Pass pre as a 2-tuple like ('a', 1) or ('alpha', 2)
- Use normalize_pre() to validate the letter before calling
- Pass None to omit the pre-release segment
When it happens
Trigger: Calling Version.from_parts(release=(1,), pre=('gamma', 1)) (invalid letter), Version.from_parts(release=(1,), pre=('a', -1)) (negative number), Version.from_parts(release=(1,), pre=('a',)) (wrong length), or Version.from_parts(release=(1,), pre='a1') (string not tuple).
Common situations: Passing a pre-release string instead of a tuple, using an unrecognized pre-release label, or a negative pre-release number from a computation.
Related errors
- dev must be non-negative integer, got
- epoch must be non-negative integer, got
- Invalid sdist filename (invalid version)
- Invalid version
- Invalid wheel filename (invalid version)
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/d45312f6908f5329.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/version.py:300
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
# The letter must be a string before it can be normalized.
if (
isinstance(letter, str)
and (normalized := normalize_pre(letter)) in {"a", "b", "rc"}
and isinstance(number, int)
and number >= 0
):
# type checkers can't infer the Literal type here on letter
return (normalized, 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 f399c37189)