{"id":"46546ce6e755dffe","repo":"pypa/pip","slug":"invalid-wheel-filename-compressed-tag-set-compone","errorCode":null,"errorMessage":"Invalid wheel filename (compressed tag set components must be in sorted order per PEP 425): {filename!r}","messagePattern":"Invalid wheel filename \\(compressed tag set components must be in sorted order per PEP 425\\): (.+?)","errorType":"validation","errorClass":"InvalidWheelFilename","httpStatus":null,"severity":"warning","filePath":"src/pip/_vendor/packaging/utils.py","lineNumber":242,"sourceCode":"        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    \"\"\"\n    This function takes the filename of a sdist file (as specified\n    in the `Source distribution format`_ documentation), and parses\n    it, returning a tuple of the normalized name and version as\n    represented by an instance of :class:`~packaging.version.Version`.\n\n    :param str filename: The name of the sdist file.\n    :raises InvalidSdistFilename: If the filename does not end\n        with an sdist extension (``.zip`` or ``.tar.gz``), or if it does not\n        contain a dash separating the name and the version of the distribution.\n","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/utils.py#L224-L260","documentation":"Raised by `parse_wheel_filename` when `parse_tag(tag_str, validate_order=True)` raises `UnsortedTagsError`, meaning the compressed tag set (the `py-abi-platform` portion, which may use `.` to combine tags) is not in sorted order per PEP 425. The wheel spec requires each tag-set component (interpreter, abi, platform runs separated by `.`) to be sorted ascending; reordering is a strictly informational validation controlled by the `validate_order` parameter (added in 26.1).","triggerScenarios":"Calling `parse_wheel_filename(fn, validate_order=True)` on a filename whose tag run is unsorted, e.g. `...-py3-none-any` is fine but a multi-tag run like `cp311.cp310-...` out of order, or an ABI/platform run not sorted. With the default `validate_order=False` this is never raised.","commonSituations":"Enabling strict ordering validation; a wheel produced by a tool that didn't sort the compressed tag sets; verifying PEP 425 compliance in a linter/CI gate.","solutions":["If you don't need strict PEP 425 ordering checks, call `parse_wheel_filename(fn)` (default `validate_order=False`).","Rebuild the wheel with a current backend that emits sorted tag runs.","Re-sort the tag runs in the filename (split on `.`, sort each component, rejoin) and rename.","Report the non-compliant wheel to its publisher."],"exampleFix":"// before\nparse_wheel_filename(fn, validate_order=True)  # raises on unsorted tags\n\n# after\nparse_wheel_filename(fn)  # validate_order defaults to False","handlingStrategy":"validation","validationCode":"def will_pass_order_check(filename: str) -> bool:\n    # The error only fires when validate_order=True; default is safe.\n    return True  # call parse_wheel_filename(fn) without validate_order=True","typeGuard":null,"tryCatchPattern":"from pip._vendor.packaging.utils import parse_wheel_filename, InvalidWheelFilename\n\ntry:\n    parse_wheel_filename(filename, validate_order=True)\nexcept InvalidWheelFilename as e:\n    if 'sorted order' in str(e):\n        # relax the check or rebuild with sorted tag runs\n        parse_wheel_filename(filename)  # validate_order=False\n    else:\n        raise","preventionTips":["Only enable `validate_order=True` when you specifically need PEP 425 strictness.","Rebuild wheels with a backend that emits sorted compressed tag sets.","Treat ordering issues as warnings, not hard failures, unless compliance gating requires it."],"tags":["python","packaging","utils","wheel","pep425","tags","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}