pypa/pip · warning · TooManyTagsError

Compressed tag set would generate {tag_count} tags, exceedin

Error message

Compressed tag set would generate {tag_count} tags, exceeding limit {limit}

What it means

Raised as TooManyTagsError (ValueError subclass) by parse_tag (tags.py:292-296) when limit is not None and the product of the sizes of all components (interpreters x abis x platforms) exceeds limit. This is a DoS-guard preventing a single compressed tag string from exploding into an enormous tag set (e.g. a tag with many alternatives in each field).

Source

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

        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:
        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
    )

View on GitHub (pinned to f399c37189)

Solutions

  1. Raise the limit to accommodate the expected tag count, or pass limit=None if you trust the source.
  2. Reduce the breadth of the compressed tag (fewer alternatives per component) so the product stays within budget.
  3. Catch TooManyTagsError and either skip the tag or report it as too broad to handle.
  4. Compute the expected product (prod(len(c.split('.')) for c in tag.split('-'))) before parsing to fail fast with your own message.

Example fix

# before
parse_tag('a.b.c.d-x.y.z-p.q.r', limit=10)  # TooManyTagsError: 24 > 10

# after - size the limit to the actual product, or trust source
from math import prod
count = prod(len(c.split('.')) for c in tag.split('-'))
parse_tag(tag, limit=count if count <= BUDGET else None)
Defensive patterns

Strategy: validation

Validate before calling

from math import prod
def expected_count(tag: str) -> int:
    return prod(len(c.split('.')) for c in tag.split('-'))

def within_budget(tag: str, limit: int) -> bool:
    return expected_count(tag) <= limit

Try / catch

from packaging.tags import TooManyTagsError
try:
    parse_tag(tag, limit=BUDGET)
except TooManyTagsError:
    skip_or_warn(tag)

Prevention

When it happens

Trigger: parse_tag('a.b.c.d-x.y.z-p.q.r', limit=10) where the product 4*3*2=24 > 10; parsing an adversarial or auto-generated compressed tag with many alternatives under a tight budget.

Common situations: A wheel resolver enforcing a tag-expansion budget to avoid quadratic blowups; processing untrusted/index-sourced tag strings; a generator that creates overly-broad compatibility tags.

Related errors


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