nodejs/node · error · InvalidVersion

Invalid version: '{version}'

Error message

Invalid version: '{version}'

What it means

packaging.version.InvalidVersion raised by Version.__init__ when the version string does not match the PEP 440 regex even after the library's lenient normalization search. This is the canonical 'not a valid version' error for the whole packaging library and underpins several wheel/sdist filename errors.

Source

Thrown at tools/gyp/pylib/packaging/version.py:200

    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
    _key: CmpKey

    def __init__(self, version: str) -> None:
        """Initialize a Version object.

        :param version:
            The string representation of a version which will be parsed and normalized
            before use.
        :raises InvalidVersion:
            If the ``version`` does not conform to PEP 440 in any way then this
            exception will be raised.
        """

        # Validate the version and parse it into pieces
        match = self._regex.search(version)
        if not match:
            raise InvalidVersion(f"Invalid version: '{version}'")

        # Store the parsed out pieces of the version
        self._version = _Version(
            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
            release=tuple(int(i) for i in match.group("release").split(".")),
            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
            post=_parse_letter_version(
                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
            ),
            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
            local=_parse_local_version(match.group("local")),
        )

        # Generate a key which will be used for sorting
        self._key = _cmpkey(
            self._version.epoch,
            self._version.release,
            self._version.pre,

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Strip leading 'v' and normalize the version to PEP 440 before constructing Version.
  2. Use packaging.version.parse() which tolerates legacy versions instead of strict Version().
  3. Catch InvalidVersion at the input boundary and report the offending string.

Example fix

# before
v = Version(tag)  # tag = 'v1.0'

# after
from packaging.version import parse
v = parse(tag.lstrip('v'))
Defensive patterns

Strategy: validation

Validate before calling

from packaging.version import Version, InvalidVersion
def is_pep440(version: str) -> bool:
    try:
        Version(version)
        return True
    except InvalidVersion:
        return False

Type guard

from packaging.version import Version
def as_version(v):
    try:
        return Version(v)
    except InvalidVersion:
        return None

Try / catch

from packaging.version import parse, Version, InvalidVersion
try:
    v = Version(raw)
except InvalidVersion:
    v = parse(raw)  # tolerates legacy forms

Prevention

When it happens

Trigger: Constructing Version('v1.0'), Version('1..0'), Version('1.0-beta'), or other non-PEP-440 strings raises. The regex uses .search() so a valid substring embedded in junk may slip through, but fully non-conforming strings fail.

Common situations: Parsing VCS tags (e.g. 'v1.0'), SCM-generated versions, date-only versions, or versions from languages with looser schemes (e.g. SemVer-with-build that PEP 440 rejects).

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/f35553890fad00fe. Report an issue: GitHub.