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.

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)

Solutions

  1. Replace the offending entry with the tool's name string or its BaseTool instance
  2. If passing decorated functions, use the returned BaseTool object, not the raw function
  3. 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

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: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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