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
- Invoke ToolNode with the graph state dict (containing the injected fields) instead of a bare message list
- If only one state field is needed, ensure the injected annotation maps to the messages key so list input can be coerced
- 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)