langchain-ai/langgraph · error · ValueError

No message found in input

Error message

No message found in input

What it means

Generic input-shape guard in ToolNode's input coercion (_parse_input): the incoming value is neither a list of messages, a ToolCallWithContext payload, a dict containing the messages key, nor an object exposing that attribute. ToolNode cannot locate any messages, so it refuses to process the input.

Solutions

  1. Invoke ToolNode with a list of messages, a dict like {"messages": [...]}, or the standard graph state
  2. If using a custom messages_key, ensure the input carries that exact key
  3. Route from the model node via tools_condition so input shape matches expectations
Defensive patterns

Strategy: validation

When it happens

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

Appendix: source

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

            isinstance(input, dict) and input.get("__type") == "tool_call_with_context"
        ):
            # Handle ToolCallWithContext from Send API
            # Type checkers cannot narrow correctly since the signature
            # for input contains dict[str, Any]. We'd need to narrow dict[str, Any]
            # before we can apply correct typing.
            input_with_ctx = cast("ToolCallWithContext", input)
            input_type = "tool_calls"
            return [input_with_ctx["tool_call"]], input_type
        elif isinstance(input, dict) and (
            messages := input.get(self._messages_key, [])
        ):
            input_type = "dict"
        elif messages := getattr(input, self._messages_key, []):
            # Assume dataclass-like state that can coerce from dict
            input_type = "dict"
        else:
            msg = "No message found in input"
            raise ValueError(msg)

        try:
            latest_ai_message = next(
                m for m in reversed(messages) if isinstance(m, AIMessage)
            )
        except StopIteration:
            msg = "No AIMessage found in input"
            raise ValueError(msg)

        tool_calls = list(latest_ai_message.tool_calls)
        return tool_calls, input_type

    def _validate_tool_call(self, call: ToolCall) -> ToolMessage | None:
        requested_tool = call["name"]
        if requested_tool not in self.tools_by_name:
            all_tool_names = list(self.tools_by_name.keys())
            content = INVALID_TOOL_NAME_ERROR_TEMPLATE.format(
                requested_tool=requested_tool,

View on GitHub (pinned to 38031739e5)