pypa/pip · error · InvalidVersion
release must be a non-empty tuple of non-negative integers…
Error message
release must be a non-empty tuple of non-negative integers, got {release} What it means
Raised by _validate_release() (version.py:273-282) when the release value passed to Version.from_parts() or Version.__replace__() is not a non-empty tuple of non-negative integers. None defaults to (0,), but any other value must be a tuple of ints where each element >= 0 and len > 0. Lists, strings, empty tuples, or tuples with negative/float/string elements all trigger this.
Solutions
- Pass release as a non-empty tuple of non-negative ints, e.g. (1, 2, 3).
- Convert lists with tuple(lst) and ensure all elements are int >= 0 before calling.
- Provide at least one release component; use (0,) for a zero version.
Example fix
// before Version.from_parts(release=[1, 0]) // after Version.from_parts(release=(1, 0))
Defensive patterns
Strategy: type-guard
Validate before calling
from packaging.version import Version, InvalidVersion
def safe_from_parts(*, release, **kwargs):
if not isinstance(release, tuple) or len(release) == 0:
raise TypeError("release must be a non-empty tuple")
if not all(isinstance(i, int) and i >= 0 for i in release):
raise TypeError("release must contain only non-negative ints")
return Version.from_parts(release=release, **kwargs) Type guard
def is_valid_release(value) -> bool:
return (
isinstance(value, tuple)
and len(value) > 0
and all(isinstance(i, int) and i >= 0 for i in value)
) Try / catch
from packaging.version import InvalidVersion
try:
v = Version.from_parts(release=release)
except InvalidVersion as e:
if "release" in str(e):
logger.error("Invalid release value: %s", release)
raise Prevention
- Pass release as a tuple of non-negative ints, never a list or string
- Convert lists with tuple() before calling
- Ensure at least one component is provided; use (0,) for zero
When it happens
Trigger: Calling Version.from_parts(release=[1, 0]) (list not tuple), Version.from_parts(release=()) (empty), Version.from_parts(release=(1, -1)) (negative), or Version.from_parts(release='1.0') (string).
Common situations: Passing a list instead of a tuple, an empty release, or release components read as strings from JSON/config that were not converted.
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/be98a9c29c89431a.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/version.py:282
def _validate_epoch(value: object, /) -> int:
epoch = value or 0
if isinstance(epoch, int) and epoch >= 0:
return epoch
msg = f"epoch must be non-negative integer, got {epoch}"
raise InvalidVersion(msg)
def _validate_release(value: object, /) -> tuple[int, ...]:
release = (0,) if value is None else value
if (
isinstance(release, tuple)
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
# 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)View on GitHub (pinned to f399c37189)