LangChain/LangGraph tool args validation middleware

Hello !

I would like to sharing a small middleware I’ve been using to harden agents against malformed tool calls.

ToolArgsValidationMiddleware validates LLM-generated tool-call arguments against each tool’s schema before the tool runs — and before any HITL approval. Invalid args → error ToolMessages → model re-invoked to self-correct, all within the model node, so only the final valid AIMessage enters state.

from langchain.agents import create_agent
from langchain_tool_args_validation_middleware import ToolArgsValidationMiddleware

agent = create_agent(model, tools=tools, middleware=[ToolArgsValidationMiddleware()])

  • Pydantic (model_validate) and MCP / dict-schema (jsonschema) tools both supported automatically; unknown tools pass through.
  • Correct multi-call batch handling — every tool_call gets a matching ToolMessage; valid siblings get a “not executed” notice and the model re-issues the corrected batch.
  • strip_empty_values removes spurious null/{}/[], writing cleaned args back so validation == execution.
  • Pluggable extra_validators for domain rules (bundled example flags LangChain internal lc_<uuid> IDs that models sometimes pass as real data).
  • Configurable retries and fail-open / fail-raise.

Repo: GitHub - Serjbory/langchain-tool-args-validation-middleware: A LangChain agent middleware that validates LLM-generated tool-call arguments against each tool's schema before the tool runs (and before any human-in-the-loop approval step) · GitHub · pip install langchain-tool-args-validation-middleware

Would love feedback on how this should sit alongside the retry middlewares, and whether the fail-open default is the right call.

Hey this is needed! I wanted a self-correcting middleware to wrap my tool calls. nice work! Just make sure its sufficiently different than trustcall, else maybe you should integrate that somehow.

this is awaited!

Thanks for the feedback :slight_smile: It’s a good point, I looked into it. They’re actually pretty different in practice.

trustcall is really a great tool — you call it to pull structured data out (or update an existing object), and its main trick is fixing schema errors with JSON patches instead of regenerating everything.

This one is more of a guardrail inside the agent loop. It’s middleware that checks the LLM’s tool-call arguments against the tool schema before the tool actually runs — and before a human gets asked to approve anything. So broken args never make it to the tool or to a reviewer, and the model fixes itself right there in the model node.

The stuff this has to deal with — partial batch failures, making sure every tool call gets a matching ToolMessage, the human-in-the-loop approval step — just isn’t on trustcall’s radar. And trustcall’s patch-based updates aren’t something a tool-call validator needs.