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
- Remove duplicate extras in the receipt entry, keeping one canonical form (e.g. `extras = ["all"]`).
- Regenerate the receipt with a single `--extra` flag per extra: `uv tool install deepagents-code --force --extra all`.
- 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
- Deduplicate extras by canonicalized name before writing receipts programmatically.
- Never append extras to a receipt repeatedly; recompute the full set each time.
- Use one `--extra` flag per unique extra when reinstalling.
- Normalize extra casing (PEP 685) in any tooling that generates extras lists.
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
- uv tool receipt contains invalid extras on the tool requirem
- uv tool receipt is missing `[tool].requirements`
- uv tool receipt contains a non-table requirement entry
- uv tool receipt contains a requirement without a package nam
- uv tool receipt is missing `[tool]`
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/81d24f538c3c1937.
Report an issue: GitHub.