langchain-ai/deepagents · error · TypeError
ptc list entries must be str or BaseTool
Error message
ptc list entries must be str or BaseTool
What it means
Within a list-form `ptc` config, every entry must be either a tool name string or a `BaseTool` instance; any other type raises TypeError. The list must remain unambiguous for name-based allowlisting.
Solutions
- Replace the offending entry with the tool's name string or its BaseTool instance
- If passing decorated functions, use the returned BaseTool object, not the raw function
- Normalize heterogeneous input: `[t.name if isinstance(t, BaseTool) else str(t) for t in items]` only for valid items
Example fix
# before
ptc=[my_tool, {"name": "websearch"}]
# after
ptc=[my_tool, "websearch"] Defensive patterns
Strategy: type-guard
Validate before calling
bad = [x for x in ptc_list if not isinstance(x, (str, BaseTool))]
if bad:
raise TypeError(f"ptc entries must be str or BaseTool, got {bad!r}") Type guard
def is_valid_ptc_entry(x: object) -> TypeGuard[Union[str, BaseTool]]:
return isinstance(x, (str, BaseTool)) Try / catch
try:
selected = filter_tools_for_ptc(tools, ptc_list)
except TypeError as e:
if "str or BaseTool" in str(e):
ptc_list = [x.name if isinstance(x, BaseTool) else str(x) for x in ptc_list if isinstance(x, (str, BaseTool))]
selected = filter_tools_for_ptc(tools, ptc_list)
else:
raise Prevention
- Use the BaseTool returned by @tool decorators, not the decorated function
- Normalize configs to strings as early as possible in the load path
- Add runtime type checks where ptc config crosses a serialization boundary (JSON/YAML)
When it happens
Trigger: Passing a ptc list containing e.g. a dict, `None`, a callable, or a tuple — anything that is not `str` or `BaseTool` — to `filter_tools_for_ptc` (via agent `ptc` config).
Common situations: Passing `@tool`-decorated function objects (which are not BaseTool instances) instead of the resulting tool; passing tool-name/description dicts; JSON config values parsed into mixed types.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Unsupported `ptc` config type. Use a list of tool names…
- cli_max_retries must be None or an int, got
- context.auto_approve must be a boolean or null, got
- context.hooks_server_events must be a list of strings or…
- context. must be a string or null, got .
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/8cbc0c0f3a1267e6.
Report an issue: GitHub.
Appendix: source
Thrown at libs/partners/quickjs/langchain_quickjs/_ptc.py:97
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:
continue
seen_names.add(tool.name)
deduped.append(tool)
selected = deduped
_raise_on_invalid_ptc_tools(selected)
return selected
msg = (
"Unsupported `ptc` config type. "
"Use a list of tool names, list of BaseTool instances, or disable PTC."
)View on GitHub (pinned to a1af029e6e)