pypa/pip · error · InvalidTag
Tag {tag!r} must have exactly three components
Error message
Tag {tag!r} must have exactly three components What it means
Raised as InvalidTag (ValueError subclass) by parse_tag (tags.py:298-301) when splitting the tag on '-' does not produce exactly three component groups (interpreter, abi, platform). The destructuring `interpreters, abis, platforms = component_parts` raises a ValueError that is wrapped into this InvalidTag. Two or four+ hyphen-delimited groups both trigger it.
Source
Thrown at src/pip/_vendor/packaging/tags.py:301
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:
if not interpreter.isidentifier():
raise InvalidTag(f"Tag {tag!r} has an invalid interpreter: {interpreter!r}")
return frozenset(
Tag(interpreter, abi, platform_)
for interpreter in interpreters
for abi in abis
for platform_ in platforms
)
def _get_config_var(name: str, warn: bool = False) -> int | str | None:
value: int | str | None = sysconfig.get_config_var(name)
if value is None and warn:
logger.debug(
"Config variable '%s' is unset, Python ABI tag may be incorrect", name
)
return valueView on GitHub (pinned to f399c37189)
Solutions
- Normalize platform tags: replace '-' and '.' with '_' (use _normalize_string / str.replace) so the tag splits into exactly three groups.
- Verify the tag has exactly two hyphens: assert tag.count('-') == 2 before parse_tag.
- If you have the three parts already, construct Tag(interpreter, abi, platform) directly instead of parse_tag.
- Catch InvalidTag and report the malformed tag to the caller.
Example fix
# before
parse_tag('py3-none-macosx-10-9-x86_64') # 5 components -> InvalidTag
# after - normalize hyphens to underscores in the platform
plat = 'macosx-10-9-x86_64'.replace('-', '_') # 'macosx_10_9_x86_64'
parse_tag(f'py3-none-{plat}') Defensive patterns
Strategy: validation
Validate before calling
def has_three_components(tag: str) -> bool:
return tag.count('-') == 2 Try / catch
from packaging.tags import InvalidTag
try:
parse_tag(tag)
except InvalidTag:
handle_malformed(tag) Prevention
- Normalize platform hyphens to underscores before parse_tag.
- Assert tag.count('-') == 2 at the boundary.
- Construct Tag(interpreter, abi, platform) directly when you have the parts.
When it happens
Trigger: parse_tag('py3-none') (2 components); parse_tag('py3-none-any-extra') (4 components); a platform string containing a hyphen that wasn't normalized to underscore (e.g. 'macosx-10-9-x86_64' style without dots).
Common situations: Wheel filenames whose platform tag legitimately contains hyphens being split naively; a tag assembled from a platform with hyphens not converted to underscores per PEP 425; truncated/corrupt tag strings.
Related errors
- Tag {tag!r} has an empty component: {component!r}
- Tag component {component!r} is not in sorted order per PEP 4
- Tag {tag!r} has an invalid interpreter: {interpreter!r}
- limit must be non-negative
- Compressed tag set would generate {tag_count} tags, exceedin
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/202d88311955ea97.
Report an issue: GitHub.