langchain-ai/deepagents · error · RuntimeError

Compiled agent does not expose a LangGraph tool node

Error message

Compiled agent does not expose a LangGraph tool node

What it means

collect_built_in_tools builds the CLI tool catalog from a compiled agent created via create_cli_agent, then calls collect_tools_from_agent. If the compiled LangGraph agent does not expose its tool node, the function returns None and this RuntimeError is raised rather than silently emitting an empty catalog — an SDK/LangGraph structural change should break `dcode tools list` loudly.

Source

Thrown at libs/code/deepagents_code/tool_catalog.py:257

    agent, _backend = create_cli_agent(
        _CatalogModel(),
        assistant_id=assistant_id,
        tools=custom_tools,
        enable_memory=False,
        enable_skills=False,
        enable_shell=True,
        enable_interpreter=enable_interpreter,
        fs_tools=fs_tools,
        # Enumeration only -- this graph is never invoked. Enforcing
        # `models.allowed` here would make a subagent that names a blocked
        # model break `dcode tools list` instead of just being unusable.
        enforce_model_policy=False,
    )
    tools = collect_tools_from_agent(agent)
    if tools is None:
        msg = "Compiled agent does not expose a LangGraph tool node"
        raise RuntimeError(msg)
    # Defensive backstop against a change in SDK behavior. The SDK's
    # `FilesystemMiddleware` omits disallowed tools from the bound node
    # entirely, so `collect_tools_from_agent` should already return only
    # allowlisted filesystem tools. If a disallowed tool *does* leak through,
    # enforcement broke on the real agent (this enumeration is built from the
    # same `create_cli_agent` the runtime uses). Return the *unfiltered* list
    # and log loudly rather than scrubbing: scrubbing would hide the one signal
    # that enforcement failed and make `/tools` report a restricted surface over
    # an unrestricted agent. (`None` — the unrestricted default — skips this.)
    if isinstance(fs_tools, list):
        enabled = frozenset(fs_tools)
        leaked = [
            tool.name
            for tool in tools
            if tool.name in _FILESYSTEM_TOOL_NAMES and tool.name not in enabled
        ]
        if leaked:
            logger.error(

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Pin/align langgraph and deepagents versions to those the SDK expects, then reinstall.
  2. Inspect the compiled agent's graph nodes and update collect_tools_from_agent for the new structure.
  3. Verify the agent is created via create_cli_agent with tool binding enabled (enforce_model_policy=False here does not disable tools).
  4. If a mock is used in tests, make it mimic the real compiled graph's tool node.

Example fix

// before
pip install -U langgraph langchain  # latest, may break internals
// after
uv sync --locked  # use the pinned lockfile versions
Defensive patterns

Strategy: try-catch

Validate before calling

compiled = create_cli_agent(...)
nodes = getattr(compiled, "nodes", None)
if not nodes or not any("tool" in str(n) for n in nodes):
    raise RuntimeError("agent graph has no tool node; check SDK versions")

Type guard

def has_tool_node(agent: object) -> TypeGuard[CompiledGraph]:
    return getattr(agent, "nodes", None) is not None and any(
        "tools" in str(name) for name in getattr(agent, "nodes", {})
    )

Try / catch

try:
    tools = collect_built_in_tools()
except RuntimeError as exc:
    logger.error("tool catalog unavailable: %s", exc)
    tools = []

Prevention

When it happens

Trigger: Calling collect_built_in_tools (or collect_catalog) with a LangGraph/SDK version where collect_tools_from_agent can no longer find the tool node on the compiled graph — e.g. after upgrading langchain/deepagents where graph internals changed, or passing an agent compiled without tool binding.

Common situations: Dependency upgrades (langchain-core, langgraph, deepagents) that rename or restructure the tool node; constructing the agent with middleware config that suppresses tool binding; mocking create_cli_agent with a plain object in tests.

Related errors


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