langchain-ai/langgraph · error · TypeError

Tool is not registered with ToolNode

Error message

Tool {name} is not registered with ToolNode

What it means

Defensive TypeError in ToolNode's per-call execution path: the requested tool came back as None and _validate_tool_call did not flag it, i.e. the tool call names a tool that is not in tools_by_name. In practice this indicates the ToolNode was built without the tool the LLM tried to call; the code comments note it should never happen if validation is working.

Solutions

  1. Pass the missing tool to ToolNode/create_react_agent so it is registered
  2. Give the tool a stable `name` and ensure the LLM-visible name matches the registered one
  3. Restrict the model's tool binding to only the tools the ToolNode knows
Defensive patterns

Strategy: validation

When it happens

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

Appendix: source

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

            input_type: Input format.
            config: Runnable configuration.

        Returns:
            ToolMessage, Command, or list of Command/ToolMessage.

        Raises:
            Exception: If tool fails and handle_tool_errors is False.
        """
        call = request.tool_call
        tool = request.tool

        # Validate tool exists when we actually need to execute it
        if tool is None:
            if invalid_tool_message := self._validate_tool_call(call):
                return invalid_tool_message
            # This should never happen if validation works correctly
            msg = f"Tool {call['name']} is not registered with ToolNode"
            raise TypeError(msg)

        # Inject state, store, and runtime right before invocation
        injected_call = self._inject_tool_args(call, request.runtime, tool)
        call_args = {**injected_call, "type": "tool_call"}

        try:
            try:
                response = tool.invoke(call_args, config)
            except ValidationError as exc:
                # Filter out errors for injected arguments
                injected = self._injected_args.get(call["name"])
                filtered_errors = _filter_validation_errors(exc, injected)
                # Use original call["args"] without injected values for error reporting
                raise ToolInvocationError(
                    call["name"], exc, call["args"], filtered_errors
                ) from exc

            # Inside try so validation errors route through _handle_tool_errors

View on GitHub (pinned to 38031739e5)