{"record":{"id":"202d88311955ea97","repo":"pypa/pip","slug":"tag-tag-r-must-have-exactly-three-components","errorCode":null,"errorMessage":"Tag {tag!r} must have exactly three components","messagePattern":"Tag (.+?) must have exactly three components","errorType":"validation","errorClass":"InvalidTag","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/tags.py","lineNumber":301,"sourceCode":"            component = \".\".join(parts)\n            raise UnsortedTagsError(\n                f\"Tag component {component!r} is not in sorted order per PEP 425\"\n            )\n\n    tag_count = 1\n    for parts in component_parts:\n        tag_count *= len(parts)\n\n    if limit is not None and tag_count > limit:\n        raise TooManyTagsError(\n            f\"Compressed tag set would generate {tag_count} tags, exceeding \"\n            f\"limit {limit}\"\n        )\n\n    try:\n        interpreters, abis, platforms = component_parts\n    except ValueError as exc:\n        raise InvalidTag(f\"Tag {tag!r} must have exactly three components\") from exc\n    for interpreter in interpreters:\n        if not interpreter.isidentifier():\n            raise InvalidTag(f\"Tag {tag!r} has an invalid interpreter: {interpreter!r}\")\n    return frozenset(\n        Tag(interpreter, abi, platform_)\n        for interpreter in interpreters\n        for abi in abis\n        for platform_ in platforms\n    )\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","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/tags.py#L283-L319","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"# before\nparse_tag('py3-none-macosx-10-9-x86_64')  # 5 components -> InvalidTag\n\n# after - normalize hyphens to underscores in the platform\nplat = 'macosx-10-9-x86_64'.replace('-', '_')  # 'macosx_10_9_x86_64'\nparse_tag(f'py3-none-{plat}')","handlingStrategy":"validation","validationCode":"def has_three_components(tag: str) -> bool:\n    return tag.count('-') == 2","typeGuard":null,"tryCatchPattern":"from packaging.tags import InvalidTag\ntry:\n    parse_tag(tag)\nexcept InvalidTag:\n    handle_malformed(tag)","preventionTips":["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."],"tags":["packaging","tags","validation","pep425"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}