{"id":"e974a5d4898040a6","repo":"pypa/pip","slug":"tag-component-component-r-is-not-in-sorted-order","errorCode":null,"errorMessage":"Tag component {component!r} is not in sorted order per PEP 425","messagePattern":"Tag component (.+?) is not in sorted order per PEP 425","errorType":"validation","errorClass":"UnsortedTagsError","httpStatus":null,"severity":"warning","filePath":"src/pip/_vendor/packaging/tags.py","lineNumber":230,"sourceCode":"    If **validate_order** is true, compressed tag set components are checked\n    to be in sorted order as required by PEP 425.\n\n    :param str tag: The tag to parse, e.g. ``\"py3-none-any\"``.\n    :param bool validate_order: Check whether compressed tag set components\n        are in sorted order.\n    :raises UnsortedTagsError: If **validate_order** is true and any compressed tag\n        set component is not in sorted order.\n\n    .. versionadded:: 26.1\n       The *validate_order* parameter.\n    \"\"\"\n    tags = set()\n    interpreters, abis, platforms = tag.split(\"-\")\n    if validate_order:\n        for component in (interpreters, abis, platforms):\n            parts = component.split(\".\")\n            if parts != sorted(parts):\n                raise UnsortedTagsError(\n                    f\"Tag component {component!r} is not in sorted order per PEP 425\"\n                )\n    for interpreter in interpreters.split(\".\"):\n        for abi in abis.split(\".\"):\n            for platform_ in platforms.split(\".\"):\n                tags.add(Tag(interpreter, abi, platform_))\n    return frozenset(tags)\n\n\ndef _get_config_var(name: str, warn: bool = False) -> int | str | None:\n    value: int | str | None = sysconfig.get_config_var(name)\n    if value is None and warn:\n        logger.debug(\n            \"Config variable '%s' is unset, Python ABI tag may be incorrect\", name\n        )\n    return value\n\n","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/tags.py#L212-L248","documentation":"Raised as UnsortedTagsError (tags.py:230), a ValueError subclass, by parse_tag(tag, validate_order=True) when any of the three hyphen-separated components of a compressed tag set is not in sorted order per PEP 425. PEP 425 requires compressed-tag components (joined by '.') to list their parts in ascending lexical order so tag sets are canonical.","triggerScenarios":"parse_tag('py2.py3-none-any', validate_order=True) is fine (['py2','py3'] is sorted), but parse_tag('py3.py2-none-any', validate_order=True) raises because ['py3','py2'] != sorted(['py3','py2']). validate_order defaults to False, so this only fires when the caller explicitly opts in.","commonSituations":"Index generators and wheel-filename validators that enforce PEP 425 canonical ordering call parse_tag with validate_order=True. A hand-written tag string, or a buggy tool concatenating tags, can produce out-of-order components. Authoring a compressed interpreter/abi/platform list backwards.","solutions":["Reorder the dotted component into sorted order: 'py3.py2' -> 'py2.py3'.","If ordering is irrelevant to your use case, call parse_tag(tag) without validate_order to skip the check.","Normalize authoring by always emitting sorted(part) before joining with '.'."],"exampleFix":"# before\nfrom pip._vendor.packaging.tags import parse_tag\ntags = parse_tag(\"cp312.cp311-none-any\", validate_order=True)  # raises\n\n# after\ntags = parse_tag(\"cp311.cp312-none-any\", validate_order=True)","handlingStrategy":"validation","validationCode":"def tag_components_sorted(tag):\n    interpreter, abi, platform = tag.split('-')\n    return all(part.split('.') == sorted(part.split('.'))\n               for part in (interpreter, abi, platform))","typeGuard":"null","tryCatchPattern":"from pip._vendor.packaging.tags import parse_tag, UnsortedTagsError\ntry:\n    tags = parse_tag(tag_str, validate_order=True)\nexcept UnsortedTagsError as e:\n    parts = tag_str.split('-')\n    tag_str = '.'.join(sorted(parts[0].split('.'))) + '-' + \\\n              '.'.join(sorted(parts[1].split('.'))) + '-' + \\\n              '.'.join(sorted(parts[2].split('.')))\n    tags = parse_tag(tag_str, validate_order=True)","preventionTips":["Always emit '.'.join(sorted(parts)) when authoring compressed tag components.","Only enable validate_order when you genuinely need PEP 425 canonical ordering."],"tags":["packaging","tags","pep425","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}