{"record":{"id":"2199e80cf6d8075a","repo":"nodejs/node","slug":"invalid-build-number-build-part-in-filename","errorCode":null,"errorMessage":"Invalid build number: {build_part} in '{filename}'","messagePattern":"Invalid build number: (.+?) in '(.+?)'","errorType":"validation","errorClass":"InvalidWheelFilename","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/packaging/utils.py","lineNumber":136,"sourceCode":"    parts = filename.split(\"-\", dashes - 2)\n    name_part = parts[0]\n    # See PEP 427 for the rules on escaping the project name.\n    if \"__\" in name_part or re.match(r\"^[\\w\\d._]*$\", name_part, re.UNICODE) is None:\n        raise InvalidWheelFilename(f\"Invalid project name: {filename}\")\n    name = canonicalize_name(name_part)\n\n    try:\n        version = Version(parts[1])\n    except InvalidVersion as e:\n        raise InvalidWheelFilename(\n            f\"Invalid wheel filename (invalid version): {filename}\"\n        ) from e\n\n    if dashes == 5:\n        build_part = parts[2]\n        build_match = _build_tag_regex.match(build_part)\n        if build_match is None:\n            raise InvalidWheelFilename(\n                f\"Invalid build number: {build_part} in '{filename}'\"\n            )\n        build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2)))\n    else:\n        build = ()\n    tags = parse_tag(parts[-1])\n    return (name, version, build, tags)\n\n\ndef parse_sdist_filename(filename: str) -> Tuple[NormalizedName, Version]:\n    if filename.endswith(\".tar.gz\"):\n        file_stem = filename[: -len(\".tar.gz\")]\n    elif filename.endswith(\".zip\"):\n        file_stem = filename[: -len(\".zip\")]\n    else:\n        raise InvalidSdistFilename(\n            f\"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):\"\n            f\" {filename}\"","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/packaging/utils.py#L118-L154","documentation":"InvalidWheelFilename raised when the wheel has 5 dashes (a build tag is present) but parts[2] does not match the build-tag regex (\\d+)(.*) - i.e. it does not start with a digit. PEP 427 requires the build number to begin with an integer.","triggerScenarios":"A wheel filename like 'mypkg-1.0.0-build7-py3-none-any.whl' where the build segment starts with a letter instead of a digit.","commonSituations":"Manually adding a build tag that violates the leading-digit rule, or a build backend bug that emits an invalid build tag.","solutions":["Format build tags as an integer optionally followed by a suffix, e.g. '7', '1.post', '3local'.","Drop the build tag entirely (use 4-dash form) if you do not need it.","Rebuild with a conformant backend."],"exampleFix":"# before\n# 'mypkg-1.0.0-build7-py3-none-any.whl'\n\n# after\n# 'mypkg-1.0.0-7-py3-none-any.whl'","handlingStrategy":"validation","validationCode":"import re\n_build_re = re.compile(r'(\\d+)(.*)')\ndef valid_build_tag(filename: str) -> bool:\n    parts = filename[:-4].split('-')\n    if len(parts) != 6:\n        return True  # no build tag present\n    return bool(_build_re.match(parts[2]))","typeGuard":null,"tryCatchPattern":"try:\n    parse_wheel_filename(fn)\nexcept InvalidWheelFilename as e:\n    if 'build number' in str(e):\n        pass  # drop or fix the build tag, rebuild","preventionTips":["Format build tags as integer-first (e.g. '1', '1.post').","Omit the build tag unless you need to re-publish the same version.","Use a compliant backend for build-tag emission."],"tags":["packaging","utils","wheel","build-tag","pep427"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}