langchain-ai/deepagents · error · ValueError

Tool call ID is required for subagent invocation

Error message

Tool call ID is required for subagent invocation

What it means

The synchronous `task` tool must attribute its result to the invoking tool call. `runtime.tool_call_id` is required to construct the returning `Command`; if it is empty/None the method raises `ValueError` since the result could not be routed back to the model.

Source

Thrown at libs/deepagents/deepagents/middleware/subagents.py:554

        """Prepare state for invocation."""
        subagent = _select_subagent(subagent_type, runtime)
        # Create a new state dict to avoid mutating the original
        subagent_state = {k: v for k, v in runtime.state.items() if k not in _EXCLUDED_STATE_KEYS}
        subagent_state = {k: v for k, v in subagent_state.items() if k not in private_state_keys}
        subagent_state["messages"] = [HumanMessage(content=description)]
        return subagent, subagent_state

    def task(
        description: str,
        subagent_type: str,
        runtime: ToolRuntime,
    ) -> str | Command:
        if subagent_type not in subagent_graphs:
            allowed_types = ", ".join([f"`{k}`" for k in subagent_graphs])
            return f"We cannot invoke subagent {subagent_type} because it does not exist, the only allowed types are {allowed_types}"
        if not runtime.tool_call_id:
            value_error_msg = "Tool call ID is required for subagent invocation"
            raise ValueError(value_error_msg)
        subagent, subagent_state = _validate_and_prepare_state(
            subagent_type,
            description,
            runtime,
        )
        # The parent's callbacks, tags and configurable reach the subagent
        # automatically: langgraph's `ensure_config` seeds each run from the
        # ambient parent config and (as of langgraph#7926) merges it per-key, so
        # the subagent's bound config still wins collisions (e.g. `lc_agent_name`,
        # `recursion_limit`) and parent metadata propagates (deepagents#3634).
        # Forwarding those keys explicitly would double-count under the merge
        # (e.g. duplicate `tags`), so we only stamp the subagent tracing tag.
        subagent_config: RunnableConfig = {"configurable": {"ls_agent_type": "subagent"}}
        with _subagent_tracing_context():
            result = subagent.invoke(subagent_state, subagent_config)
        return _return_command_with_state_update(result, runtime.tool_call_id)

    async def atask(

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Invoke `task` through the agent so the framework supplies `tool_call_id`
  2. If calling directly, set a non-empty `tool_call_id` on the runtime/tool-call object
  3. Update tests to simulate a proper ToolCall/InstrumentedRuntime

Example fix

// before
runtime = SimpleNamespace(tool_call_id=None)
task(runtime, description="do it", subagent_type="researcher")
// after
runtime = SimpleNamespace(tool_call_id="call_123")
task(runtime, description="do it", subagent_type="researcher")
Defensive patterns

Strategy: try-catch

Validate before calling

if not getattr(runtime, "tool_call_id", None):
    raise RuntimeError("task() must be invoked within a tool call context")

Type guard

def in_tool_call_context(runtime) -> bool:
    return bool(getattr(runtime, "tool_call_id", None))

Try / catch

try:
    result = task(runtime, description=desc, subagent_type=kind)
except ValueError as e:
    if "Tool call ID" in str(e):
        logger.error("task() called outside a tool-call context")
    raise

Prevention

When it happens

Trigger: Calling the sync `task` tool implementation outside a real tool-call context (e.g. invoking the tool's `func` directly with a fabricated `Runtime` whose `tool_call_id` is None or empty).

Common situations: Unit tests invoking the tool function manually; custom runners executing tool bodies without a tool-call id; reusing a runtime object across calls.

Related errors


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