Implementation:Langchain ai Langgraph ValidationNode
| Attribute | Value |
|---|---|
| Source | `libs/prebuilt/langgraph/prebuilt/tool_validator.py` (221 lines) |
| Domain | Prebuilt, Validation |
| Principle | Tool_Validation |
| Library | prebuilt |
| Import | `from langgraph.prebuilt.tool_validator import ValidationNode` |
| Status | Deprecated -- Use `create_agent` from `langchain.agents` with custom tool error handling instead. |
Overview
The `tool_validator.py` module provides the `ValidationNode` class, a prebuilt graph node that validates tool calls from an AI model's output against Pydantic schemas. It returns `ToolMessage` objects with either the validated content or error messages, enabling a retry loop where the model can self-correct invalid tool calls. This class is deprecated as of LangGraph v1.0.
Description
`ValidationNode(RunnableCallable)` is a graph node designed for use in a `StateGraph` with a `"messages"` key. It does not execute the tools -- it only validates the tool call arguments against their Pydantic schemas. This is useful for:
- Structured output extraction where schema conformance is required.
- Multi-turn conversations where tool IDs must be preserved.
- Re-prompting loops that feed validation errors back to the model.
The node accepts schemas in three forms:
- Pydantic `BaseModel` classes -- Used directly for validation.
- `BaseTool` instances -- The `args_schema` attribute is extracted and used.
- Callable functions -- A schema is auto-generated from the function signature via `create_schema_from_function`.
When multiple tool calls are present in the last `AIMessage`, they are validated in parallel using a thread pool executor.
Error Handling
If validation fails (`ValidationError`), a `ToolMessage` is returned with:
- The formatted error string (from `format_error` or the default formatter).
- `additional_kwargs={"is_error": True}` to flag the message as an error.
The default error formatter produces: `"{repr(error)}\n\nRespond after fixing all validation errors."`
Output Format
The node detects the input format and returns accordingly:
- If input is a `list` of messages, returns a `list[ToolMessage]`.
- If input is a `dict` with a `"messages"` key, returns `{"messages": list[ToolMessage]}`.
Usage
from langgraph.prebuilt import ValidationNode
from pydantic import BaseModel
class MySchema(BaseModel):
name: str
age: int
# Note: ValidationNode is deprecated
node = ValidationNode([MySchema])
Code Reference
ValidationNode Class
| Method | Signature | Description |
|---|---|---|
| `__init__` | `(schemas, *, format_error=None, name="validation", tags=None)` | Initialize with schemas and optional error formatter. |
| `_get_message` | `(input) -> tuple[str, AIMessage]` | Extract the last `AIMessage` from input. |
| `_func` | dict` | Validate tool calls and return results. |
__init__ Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| `schemas` | type[BaseModel] | Callable]` | required | Schemas to validate tool calls against. |
| `format_error` | None` | `None` | Custom error formatting function. Receives `(error, ToolCall, schema)`. |
| `name` | `str` | `"validation"` | Name for the node. |
| `tags` | None` | `None` | Tags to add to the node. |
Instance Attributes
| Attribute | Type | Description |
|---|---|---|
| `schemas_by_name` | `dict[str, type[BaseModel]]` | Mapping from schema/tool name to Pydantic model class. |
| `_format_error` | `Callable` | The error formatting function. |
I/O Contract
| Aspect | Detail |
|---|---|
| Input | `list[AnyMessage]` or `dict` with `"messages"` key. The last message must be an `AIMessage` with `tool_calls`. |
| Output | `list[ToolMessage]` (if input was a list) or `{"messages": list[ToolMessage]}` (if input was a dict). |
| Side Effects | None. The node only validates; it does not execute tools. |
| Errors | Raises `ValueError` if a tool has no `args_schema`, if the last message is not an `AIMessage`, or if an unsupported schema type is provided. |
| Deprecation | Emits `LangGraphDeprecatedSinceV10` warning on class instantiation. |
Usage Examples
Validation with Re-prompting Loop
from typing import Literal, Annotated
from typing_extensions import TypedDict
from langchain_anthropic import ChatAnthropic
from pydantic import BaseModel, field_validator
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import ValidationNode
from langgraph.graph.message import add_messages
class SelectNumber(BaseModel):
a: int
@field_validator("a")
def a_must_be_meaningful(cls, v):
if v != 37:
raise ValueError("Only 37 is allowed")
return v
builder = StateGraph(Annotated[list, add_messages])
llm = ChatAnthropic(model="claude-3-5-haiku-latest").bind_tools([SelectNumber])
builder.add_node("model", llm)
builder.add_node("validation", ValidationNode([SelectNumber]))
builder.add_edge(START, "model")
def should_validate(state: list) -> Literal["validation", "__end__"]:
if state[-1].tool_calls:
return "validation"
return END
builder.add_conditional_edges("model", should_validate)
def should_reprompt(state: list) -> Literal["model", "__end__"]:
for msg in state[::-1]:
if msg.type == "ai":
return END
if msg.additional_kwargs.get("is_error"):
return "model"
return END
builder.add_conditional_edges("validation", should_reprompt)
graph = builder.compile()
Custom Error Formatting
from langgraph.prebuilt import ValidationNode
from pydantic import BaseModel
class UserProfile(BaseModel):
name: str
email: str
def custom_format(error, call, schema):
return f"Validation failed for {call['name']}: {error}. Please fix and retry."
node = ValidationNode([UserProfile], format_error=custom_format)
Related Pages
- Heuristic:Langchain_ai_Langgraph_Deprecation_Migration_Guide
- Langchain_ai_Langgraph_Warnings -- `LangGraphDeprecatedSinceV10` used as the deprecation category.
- Langchain_ai_Langgraph_Error_Classes -- Core error classes in the LangGraph framework.
- Langchain_ai_Langgraph_Public_Constants -- `START` and `END` used in graph construction examples.