langchain-ai/deepagents · error · ToolRequirementIntrospectionError

uv tool receipt contains duplicate canonical extra names

Error message

uv tool receipt contains duplicate canonical extra names

What it means

After canonicalizing extra names (PEP 685 normalization), two or more extras collapse to the same canonical name (e.g. "All" and "all"), which would produce a duplicated `--extra` flag in the reconstructed install command. The library rejects the receipt rather than emitting a broken command.

Source

Thrown at libs/code/deepagents_code/update_check.py:3059

        )
        if unsupported_keys:
            fields = ", ".join(unsupported_keys)
            msg = (
                f"uv tool receipt requirement {name!r} uses source fields "
                f"that cannot be preserved automatically: {fields}"
            )
            raise ToolRequirementIntrospectionError(msg)
        extras = entry.get("extras", [])
        if not isinstance(extras, list) or any(
            not isinstance(extra, str) or not is_valid_extra_name(extra)
            for extra in extras
        ):
            msg = "uv tool receipt contains invalid extras on the tool requirement"
            raise ToolRequirementIntrospectionError(msg)
        normalized = {canonicalize_name(extra) for extra in extras}
        if len(normalized) != len(extras):
            msg = "uv tool receipt contains duplicate canonical extra names"
            raise ToolRequirementIntrospectionError(msg)
        return normalized

    msg = f"uv tool receipt does not contain a {distribution_name!r} requirement"
    raise ToolRequirementIntrospectionError(msg)


def _uv_tool_with_packages(
    *,
    distribution_name: str = "deepagents-code",
    tool_root: Path | None = None,
    data: dict[str, Any] | None = None,
) -> tuple[str, ...]:
    """Return package names recorded as uv tool `--with` requirements.

    uv records the tool's requested requirements in `uv-receipt.toml`. Reading
    that receipt preserves only packages the user asked uv to keep, avoiding the
    over-broad fallback of promoting every installed transitive dependency to a
    top-level `--with` requirement.

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Remove duplicate extras in the receipt entry, keeping one canonical form (e.g. `extras = ["all"]`).
  2. Regenerate the receipt with a single `--extra` flag per extra: `uv tool install deepagents-code --force --extra all`.
  3. Deduplicate with canonicalized names before writing receipts if you generate them programmatically.

Example fix

// before
 extras = ["all", "ALL"]
// after
 extras = ["all"]
Defensive patterns

Strategy: validation

Validate before calling

from packaging.utils import canonicalize_name
import tomllib

def extras_deduped(data: dict, dist: str = 'deepagents-code') -> bool:
    for entry in (data.get('tool') or {}).get('requirements', []):
        if isinstance(entry, dict) and entry.get('name') == dist:
            extras = entry.get('extras', [])
            return len({canonicalize_name(e) for e in extras}) == len(extras)
    return True

Type guard

def extras_unique(value: object) -> bool:
    if not isinstance(value, list) or not all(isinstance(e, str) for e in value):
        return False
    from packaging.utils import canonicalize_name
    return len({canonicalize_name(e) for e in value}) == len(value)

Try / catch

try:
    extras = _uv_tool_selected_extras()
except ToolRequirementIntrospectionError:
    subprocess.run(['uv', 'tool', 'install', 'deepagents-code', '--force'], check=True)
    extras = _uv_tool_selected_extras()

Prevention

When it happens

Trigger: _uv_tool_selected_extras builds {canonicalize_name(extra) for extra in extras} and raises when the set size differs from the list length — i.e. duplicate extras differing only by case/punctuation; reached via _uv_tool_install_command, dependency_refresh_dry_run_command, removable_extras, or uninstall_extra_command.

Common situations: Receipt hand-edited with both "all" and "ALL"; a script appending extras on each install without deduplication; a receipt produced by tooling that does not normalize names.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/81d24f538c3c1937. Report an issue: GitHub.