pypa/pip · warning · UnsortedTagsError
Tag component is not in sorted order per PEP 425
Error message
Tag component {component!r} is not in sorted order per PEP 425 What it means
Raised as UnsortedTagsError (ValueError subclass) by parse_tag (tags.py:282-286) only when validate_order=True and a compressed component's '.'-separated parts are not in ascending sorted order. PEP 425 requires compressed tag components to be sorted so index lookups can short-circuit; this check enforces it. The comparison is lexicographic string sort (parts != sorted(parts)).
Solutions
- Sort each '.'-separated component lexicographically before emitting the tag string.
- If the order is intentional for your tool, omit validate_order (it defaults to False).
- Use parse_tag without validate_order for tolerant parsing, and apply ordering only when emitting canonical tags.
- Catch UnsortedTagsError and re-sort the component automatically, then re-parse.
Example fix
# before
parse_tag('py3.py2-none-any', validate_order=True) # UnsortedTagsError
# after - emit components in sorted order
comp = '.'.join(sorted(['py3', 'py2'])) # 'py2.py3'
parse_tag(f'{comp}-none-any', validate_order=True) Defensive patterns
Strategy: validation
Validate before calling
def sorted_component(comp: str) -> str:
return '.'.join(sorted(comp.split('.')))
# then build the tag with each component pre-sorted Type guard
def components_sorted(tag: str) -> bool:
return all(p.split('.') == sorted(p.split('.')) for p in tag.split('-')) Try / catch
from packaging.tags import UnsortedTagsError
try:
parse_tag(tag, validate_order=True)
except UnsortedTagsError:
tag = '-'.join(sorted_component(c) for c in tag.split('-'))
parse_tag(tag, validate_order=True) Prevention
- Always emit compressed components in sorted order.
- Only enable validate_order when spec compliance is required.
- Auto-sort offending components and re-parse.
When it happens
Trigger: parse_tag('py3.py2-none-any', validate_order=True) (['py3','py2'] != sorted ['py2','py3']); parse_tag('cp310.cp39-...', validate_order=True); any compressed tag where a higher version precedes a lower one within a component.
Common situations: A wheel index/mirror tool enforcing PEP 425 ordering on submitted compressed tags; a build tool generating py2.py3 tags in the wrong order; validating user-uploaded wheel filenames for spec compliance.
Related errors
- Tag has an empty component
- Tag has an invalid interpreter
- Tag must have exactly three components
- Compressed tag set would generate
- Invalid wheel filename (compressed tag set components must…
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/e974a5d4898040a6.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/tags.py:284
.. versionadded:: 26.3
Raises :class:`InvalidTag` when an interpreter component is not an
identifier, a tag component is empty, or a tag does not have exactly
three components.
Added the *limit* parameter. Raises :class:`TooManyTagsError` if the compressed
tag set would generate more than *limit* tags.
"""
if limit is not None and limit < 0:
raise ValueError("limit must be non-negative")
component_parts = [component.split(".") for component in tag.split("-")]
for parts in component_parts:
if "" in parts:
component = ".".join(parts)
raise InvalidTag(f"Tag {tag!r} has an empty component: {component!r}")
if validate_order and parts != sorted(parts):
component = ".".join(parts)
raise UnsortedTagsError(
f"Tag component {component!r} is not in sorted order per PEP 425"
)
tag_count = 1
for parts in component_parts:
tag_count *= len(parts)
if limit is not None and tag_count > limit:
raise TooManyTagsError(
f"Compressed tag set would generate {tag_count} tags, exceeding "
f"limit {limit}"
)
try:
interpreters, abis, platforms = component_parts
except ValueError as exc:
raise InvalidTag(f"Tag {tag!r} must have exactly three components") from exc
for interpreter in interpreters:View on GitHub (pinned to f399c37189)