langchain-ai/deepagents · error · ProtectedExtraError

Extra {extra!r} is a base dependency and cannot be removed.

Error message

Extra {extra!r} is a base dependency and cannot be removed.

What it means

Raised when the requested extra is one of the BASE_DEPENDENCY_EXTRAS shipped with the tool by default. Base extras are integral to the distribution and cannot be removed independently. The check compares the canonicalized name against the protected set before consulting installed extras.

Source

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

        CompositeExtraConflictError: If a selected composite supplies `extra`.
        ExtraNotInstalledError: If `extra` is not selected in this install.

    Propagates `ToolRequirementIntrospectionError` if the uv tool receipt cannot
    be read, or does not safely describe the selected extras, the interpreter, or
    the `--with` packages.
    """
    if not is_valid_extra_name(extra):
        msg = (
            f"Invalid extra name {extra!r}: must match PEP 508 "
            f"({_EXTRA_NAME_RE.pattern})"
        )
        raise ValueError(msg)
    from deepagents_code.extras_info import BASE_DEPENDENCY_EXTRAS

    selected_extra = canonicalize_name(extra)
    if selected_extra in BASE_DEPENDENCY_EXTRAS:
        msg = f"Extra {extra!r} is a base dependency and cannot be removed."
        raise ProtectedExtraError(msg)

    extras = _uv_tool_selected_extras(distribution_name=distribution_name)
    conflict = _composite_extra_conflict_message(extra, selected=extras)
    if conflict is not None:
        raise CompositeExtraConflictError(conflict)
    if selected_extra not in extras:
        listed = ", ".join(sorted(extras)) or "(none)"
        msg = f"Extra {extra!r} is not installed. Selected extras: {listed}"
        raise ExtraNotInstalledError(msg)
    return _uv_tool_install_command(
        version=version,
        include_prereleases=_resolve_include_prereleases(
            None, installed=_parse_version(version)
        ),
        distribution_name=distribution_name,
        extras_to_remove=(selected_extra,),
        reinstall=True,
    )

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Remove only genuinely optional extras; check BASE_DEPENDENCY_EXTRAS (deepagents_code.extras_info) to see which names are protected.
  2. If the goal is a minimal install, reinstall the tool without extras rather than removing base ones.
  3. If you really need different base dependencies, use a different distribution or install method instead of the tool-extras flow.

Example fix

// before
remove_extra('core')  # base dependency
// after
remove_extra('search-tools')  # optional extra
Defensive patterns

Strategy: validation

Validate before calling

from deepagents_code.extras_info import BASE_DEPENDENCY_EXTRAS
from packaging.utils import canonicalize_name
if canonicalize_name(name) in BASE_DEPENDENCY_EXTRAS:
    raise ValueError(f'{name} is a base dependency and cannot be removed')

Try / catch

try:
    remove_extra(name)
except ProtectedExtraError as e:
    logger.warning('skipping protected extra: %s', e)

Prevention

When it happens

Trigger: Calling the remove-extra API (update_check.py) with an extra whose canonical name is in BASE_DEPENDENCY_EXTRAS, e.g. attempting to remove a core bundled extra by any casing/normalization variant.

Common situations: Trying to slim down the installation by removing what looks like an optional extra but is actually a base dependency; scripting bulk removal of all extras including base ones.

Related errors


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