langchain-ai/deepagents · error · ValueError
The subagent `task` tool cannot be exposed via `ptc`. It is
Error message
The subagent `task` tool cannot be exposed via `ptc`. It is always available as the top-level `task()` global inside the REPL (with `subagentType`, `label`, and `responseSchema` support); exposing it through the `tools.*` namespace would create a second, conflicting dispatch path that drops `responseSchema`. Remove "task" from `ptc`.
What it means
The `task` subagent tool is reserved: it is always injected as the top-level `task()` REPL global with full support for `subagentType`, `label`, and `responseSchema`. Exposing it through the `ptc` tools namespace would create a conflicting second dispatch path that silently drops `responseSchema`, so listing it in a ptc include list raises.
Source
Thrown at libs/partners/quickjs/langchain_quickjs/_ptc.py:87
Duplicate tool names are deduplicated.
The subagent `task` tool is reserved and may not appear in `config`
(by name or instance) — it is always available as the `task()` global,
so a `tools.task` PTC variant would be a conflicting, degraded duplicate.
A `"task"` entry raises `ValueError`.
Warning:
PTC tool calls execute through the REPL bridge and currently do
not respect `interrupt_on` / HITL approval hooks for each
individual tool invocation.
"""
if isinstance(config, list):
explicit_tools: list[BaseTool] = []
allow_names: set[str] = set()
for entry in config:
if isinstance(entry, BaseTool):
if entry.name == _RESERVED_SUBAGENT_TASK_NAME:
raise ValueError(_TASK_IN_PTC_MSG)
if entry.name != self_tool_name:
explicit_tools.append(entry)
continue
if isinstance(entry, str):
if entry == _RESERVED_SUBAGENT_TASK_NAME:
raise ValueError(_TASK_IN_PTC_MSG)
allow_names.add(entry)
continue
msg = "ptc list entries must be str or BaseTool"
raise TypeError(msg)
selected = [
*explicit_tools,
*[t for t in tools if t.name != self_tool_name and t.name in allow_names],
]
deduped: list[BaseTool] = []
seen_names: set[str] = set()
for tool in selected:
if tool.name in seen_names:View on GitHub (pinned to a1af029e6e)
Solutions
- Remove `"task"` from the ptc list config
- Filter reserved tool names before constructing the ptc list
- Rely on the built-in `task()` global — no ptc exposure is needed for subagent spawning
Example fix
// before const ptc = ["websearch", "task"]; // after const ptc = ["websearch"];
Defensive patterns
Strategy: validation
Validate before calling
if any(getattr(t, "name", None) == "task" for t in tool_objects):
raise ValueError("remove reserved 'task' tool from ptc list") Type guard
def is_ptc_safe_tool(t: BaseTool) -> bool:
return t.name != "task" Try / catch
try:
selected = filter_tools_for_ptc(tools, config)
except ValueError as e:
if "task" in str(e) and "ptc" in str(e):
config = [t for t in config if (t.name if isinstance(t, BaseTool) else t) != "task"]
selected = filter_tools_for_ptc(tools, config)
else:
raise Prevention
- Keep a RESERVED_TOOL_NAMES = {"task"} constant and filter lists against it
- Never enumerate the full tool registry into ptc config unfiltered
- Remember subagent spawning is always available via the top-level task() global
When it happens
Trigger: Calling `filter_tools_for_ptc` (directly or via `_prepare_for_call`) with a list-form `ptc` config that includes the `task` tool instance or the string `"task"`.
Common situations: Passing through all agent tools including the subagent task tool; building a tool allowlist from a tool registry without filtering reserved names; users explicitly requesting 'task' in their ptc tool list.
Related errors
- ptc list entries must be str or BaseTool
- PTC tool name {tool.name!r} cannot be exposed as JavaScript
- Context tool names conflict with criteria-agent tools: {name
- Unsupported `ptc` config type. Use a list of tool names, lis
- QuickJS context is closed
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/b9853cdc8a331861.
Report an issue: GitHub.