{"id":"d332fe76a25b1dee","repo":"pypa/pip","slug":"invalid-build-number-build-part-in-filename-r","errorCode":null,"errorMessage":"Invalid build number: {build_part} in {filename!r}","messagePattern":"Invalid build number: (.+?) in (.+?)","errorType":"validation","errorClass":"InvalidWheelFilename","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/utils.py","lineNumber":232,"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!r}\")\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!r}\"\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!r}\"\n            )\n        build = cast(\"BuildTag\", (int(build_match.group(1)), build_match.group(2)))\n    else:\n        build = ()\n    tag_str = parts[-1]\n    try:\n        tags = parse_tag(tag_str, validate_order=validate_order)\n    except UnsortedTagsError:\n        raise InvalidWheelFilename(\n            f\"Invalid wheel filename (compressed tag set components must be in \"\n            f\"sorted order per PEP 425): {filename!r}\"\n        ) from None\n    return (name, version, build, tags)\n\n\ndef parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]:\n    \"\"\"","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/utils.py#L214-L250","documentation":"Raised by `parse_wheel_filename` when a build tag is present (the filename has 5 dashes, indicating 6 parts) but the build segment does not match `_build_tag_regex = r'(\\d+)(.*)'` — i.e. it does not start with one or more digits. PEP 427 requires the build number to begin with a digit, optionally followed by any other characters.","triggerScenarios":"A wheel filename like `foo-1.0-abc1-py3-none-any.whl` where the build tag `abc1` does not start with a digit; or `foo-1.0--py3-none-any.whl` (empty build segment).","commonSituations":"Hand-built wheels with a custom build tag; an old/non-compliant backend; misinterpretation of the optional build-tag slot.","solutions":["Ensure the build tag, when present, begins with a digit (e.g. `1`, `1abc`, `2final`).","Omit the build tag entirely if you don't need it (use a 5-part, 4-dash filename).","Rebuild with a compliant backend that emits build tags correctly.","Rename the file to a build tag matching `^\\d+.*$`."],"exampleFix":"// before\nparse_wheel_filename('foo-1.0-abc-py3-none-any.whl')  # build 'abc' has no leading digit\n\n# after\nparse_wheel_filename('foo-1.0-1abc-py3-none-any.whl')","handlingStrategy":"validation","validationCode":"import re\n_BUILD_RE = re.compile(r'(\\d+)(.*)', re.ASCII)\n\ndef has_valid_build_tag(filename: str) -> bool:\n    if not filename.endswith('.whl'):\n        return True\n    stem = filename[:-4]\n    if stem.count('-') != 5:\n        return True  # no build tag present\n    # build tag is the 3rd segment after splitting on first/last 2 dashes\n    parts = stem.split('-', stem.count('-') - 2)\n    return bool(_BUILD_RE.match(parts[2]))","typeGuard":null,"tryCatchPattern":"from pip._vendor.packaging.utils import parse_wheel_filename, InvalidWheelFilename\n\ntry:\n    parse_wheel_filename(filename)\nexcept InvalidWheelFilename as e:\n    if 'Invalid build number' in str(e):\n        # make the build tag start with a digit, or drop it\n        ...\n    raise","preventionTips":["When adding a build tag, always start it with a digit (`1`, `1abc`).","Prefer omitting the build tag unless you need it.","Use a current backend that emits build tags per PEP 427."],"tags":["python","packaging","utils","wheel","pep427","build-tag","filename"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}