langchain-ai/langgraph · error · ValueError

Invalid input to ToolNode. Tool

Error message

Invalid input to ToolNode. Tool {name} requires graph state dict as input.

What it means

State-injection guard in _inject_tool_args: a tool declares InjectedState annotations requiring specific graph state fields, but ToolNode received a plain list of messages (or a list that cannot be coerced to the required state dict). The tool needs the full state dict to inject its arguments.

Solutions

  1. Invoke ToolNode with the graph state dict (containing the injected fields) instead of a bare message list
  2. If only one state field is needed, ensure the injected annotation maps to the messages key so list input can be coerced
  3. Remove InjectedState annotations if the tool should work on plain message lists
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at libs/prebuilt/langgraph/prebuilt/tool_node.py:1387 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/b124d5e53afd81dd. Report an issue: GitHub.

Appendix: source

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

            # Handle list state by converting to dict
            if isinstance(state, list):
                required_fields = list(injected.state.values())
                if (
                    len(required_fields) == 1
                    and required_fields[0] == self._messages_key
                ) or required_fields[0] is None:
                    state = {self._messages_key: state}
                else:
                    err_msg = (
                        f"Invalid input to ToolNode. Tool {tool_call['name']} requires "
                        f"graph state dict as input."
                    )
                    if any(state_field for state_field in injected.state.values()):
                        required_fields_str = ", ".join(f for f in required_fields if f)
                        err_msg += (
                            f" State should contain fields {required_fields_str}."
                        )
                    raise ValueError(err_msg)

            # Extract state values
            if isinstance(state, dict):
                for tool_arg, state_field in injected.state.items():
                    if not state_field:
                        injected_args[tool_arg] = state
                    elif state_field in state:
                        injected_args[tool_arg] = state[state_field]
                    elif tool_arg not in injected._optional_state_args:
                        raise KeyError(state_field)
            else:
                for tool_arg, state_field in injected.state.items():
                    if not state_field:
                        injected_args[tool_arg] = state
                    elif hasattr(state, state_field):
                        injected_args[tool_arg] = getattr(state, state_field)
                    elif tool_arg not in injected._optional_state_args:
                        raise AttributeError(state_field)

View on GitHub (pinned to 38031739e5)