langchain-ai/langgraph · error · ValueError

Tools can provide a dict in Command.update only when using…

Error message

Tools can provide a dict in Command.update only when using dict with '{messages_key}' key as ToolNode input, got: {update} for tool '{name}'

What it means

Shape check in _validate_tool_command: the tool returned a Command whose update is a dict, but ToolNode was invoked with a list-of-messages input. Dict updates (keyed by state key like 'messages') are only meaningful when the node input is a state dict; otherwise the keys cannot be mapped.

Solutions

  1. Return the update as a list of messages: `Command(update=[ToolMessage(...)])` when invoking ToolNode with a message list
  2. Or invoke ToolNode with a dict state ({"messages": [...]}) so dict updates are allowed
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at libs/prebuilt/langgraph/prebuilt/tool_node.py:1520 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of langchain-ai/langgraph@38031739e5 (2026-08-26). Data as JSON: /api/errors/e55055631b686951. Report an issue: GitHub.

Appendix: source

Thrown at libs/prebuilt/langgraph/prebuilt/tool_node.py:1520

    def _validate_tool_command(
        self,
        command: Command,
        call: ToolCall,
        input_type: Literal["list", "dict", "tool_calls"],
        *,
        require_terminator: bool = True,
    ) -> Command:
        if isinstance(command.update, dict):
            # input type is dict when ToolNode is invoked with a dict input
            # (e.g. {"messages": [AIMessage(..., tool_calls=[...])]})
            if input_type not in ("dict", "tool_calls"):
                msg = (
                    "Tools can provide a dict in Command.update only when using dict "
                    f"with '{self._messages_key}' key as ToolNode input, "
                    f"got: {command.update} for tool '{call['name']}'"
                )
                raise ValueError(msg)

            updated_command = deepcopy(command)
            state_update = cast("dict[str, Any]", updated_command.update) or {}
            messages_update = state_update.get(self._messages_key, [])
        elif isinstance(command.update, list):
            # Input type is list when ToolNode is invoked with a list input
            # (e.g. [AIMessage(..., tool_calls=[...])])
            if input_type != "list":
                msg = (
                    "Tools can provide a list of messages in Command.update "
                    "only when using list of messages as ToolNode input, "
                    f"got: {command.update} for tool '{call['name']}'"
                )
                raise ValueError(msg)

            updated_command = deepcopy(command)
            messages_update = updated_command.update
        else:

View on GitHub (pinned to 38031739e5)