pypa/pip · error · InvalidTag

Tag {tag!r} has an empty component: {component!r}

Error message

Tag {tag!r} has an empty component: {component!r}

What it means

Raised as InvalidTag (ValueError subclass) by parse_tag (tags.py:279-281) when splitting a component on '.' yields an empty string, meaning the tag has an empty component. This catches leading/trailing dots, double dots, or a leading/trailing hyphen that produces an empty component group. The reported component is the '.'-joined part that contained the gap.

Source

Thrown at src/pip/_vendor/packaging/tags.py:281

    .. versionadded:: 26.1
       The *validate_order* parameter.

    .. 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

View on GitHub (pinned to f399c37189)

Solutions

  1. Sanitize/validate the tag string before calling parse_tag: ensure no leading/trailing '-' or '.', no consecutive '.' or '-'.
  2. Build tags from non-empty parts only; skip empty components in the generator.
  3. Use the Tag(interpreter, abi, platform) constructor with pre-validated non-empty strings instead of parse_tag for single tags.
  4. Catch InvalidTag and report the offending tag string to the user/operator.

Example fix

# before
parse_tag(f'{interp}-{abi}-{plat}')  # plat='' -> InvalidTag: empty component

# after - validate non-empty parts
parts = [interp, abi, plat]
assert all(parts), 'tag components must be non-empty'
parse_tag('-'.join(parts))
Defensive patterns

Strategy: validation

Validate before calling

import re
def is_well_formed_tag(tag: str) -> bool:
    # no empty components: no leading/trailing - or ., no consecutive separators
    return bool(tag) and not re.search(r'(?:^|[-.])[-.](?:[-.]|$)', tag)

Try / catch

from packaging.tags import InvalidTag
try:
    parse_tag(tag)
except InvalidTag:
    handle_bad_tag(tag)

Prevention

When it happens

Trigger: parse_tag('py3-.cpython310-any') (leading dot in a component); parse_tag('py3-cp310-') (trailing hyphen -> empty platform group); parse_tag('py3-..-any'); parse_tag('-none-any') (leading hyphen).

Common situations: Malformed wheel tag strings read from a filename or index; programmatic tag assembly with f-strings where a field was empty (f'{interp}-{abi}-{plat}' with plat=''); user input for a custom platform tag with stray punctuation.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/62d379c920348f7e. Report an issue: GitHub.