pypa/pip · error · ValueError

limit must be non-negative

Error message

limit must be non-negative

What it means

Raised as ValueError by parse_tag (tags.py:274-275) when the limit keyword argument is not None and is negative. The limit caps how many tags a compressed tag set may expand to; a negative cap is meaningless, so it is rejected before any parsing begins.

Source

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

        interpreter, ABI, or platform field (or any member of a compressed tag
        set) is empty; or if the tag does not have exactly three components.
    :raises TooManyTagsError: If **limit** is not ``None`` and the compressed tag
        set would generate more than **limit** tags.
    :raises ValueError: If **limit** is negative.

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

View on GitHub (pinned to f399c37189)

Solutions

  1. Use limit=None to mean 'no cap' rather than a negative sentinel.
  2. Clamp the computed limit to max(0, value) before passing.
  3. Validate user-supplied limit: if value is None or value >= 0 pass through, else raise your own clear error.
  4. If a value like -1 is your 'unlimited' convention, translate it to None at the boundary.

Example fix

# before
parse_tag('py3-none-any', limit=budget - overshoot)  # may be -1 -> ValueError

# after
limit = None if budget is None else max(0, budget - overshoot)
parse_tag('py3-none-any', limit=limit)
Defensive patterns

Strategy: validation

Validate before calling

def clamp_limit(v):
    return None if v is None else max(0, int(v))

Type guard

def is_valid_limit(v) -> bool:
    return v is None or (isinstance(v, int) and v >= 0)

Prevention

When it happens

Trigger: parse_tag('py3-none-any', limit=-1); passing a limit computed from a subtraction that went negative (e.g. budget - overshoot); a CLI/config value parsed as a signed int where 0/-1 was used as 'unlimited' by mistake.

Common situations: A wheel-tag budget calculator that underflows; config defaulting to -1 meaning 'no limit' in another tool but fed to packaging's limit which expects None for unlimited; off-by-one in a tag-count estimator.

Related errors


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