kmail.at
← learning

langchain · difficulty ◆◆◆

ChatOpenAI Tool-Call Filtering via _convert_responses_to_tool_calls

Drop the malformed tool calls before they crash your agent loop.

Models rarely emit a malformed tool call - but when they do, your entire agent loop can die on it.

2026-08-11 · 9 min read

$ pip install -U langchain-openai==1.4.3

What it does

langchain-openai==1.4.3 ships a bug fix that filters invalid tool calls from model content (#39366). With ChatOpenAI\u2019s Responses API and bind_tools, the model can occasionally emit a malformed tool call - one whose id is missing, whose arguments fail to parse as JSON, or that references a tool name not in your bound schema. Previously these passed straight through to your loop, raising confusing KeyError/JSONDecodeError exceptions deep in your agent code. Now LangChain detects and drops them, so your tool_calls list only ever contains well-formed entries.

Why it matters

Tool calling is the backbone of every agentic app - a ReAct loop, a function-calling router, a multi-step research agent all depend on trustworthy tool calls. A single malformed call can crash an entire agent run in production, and because models rarely emit bad calls, it is intermittent and brutal to reproduce. This fix hardens your loop for free: you no longer need defensive try/except wrappers around every tool dispatch to guard against garbage from the model.

Example

$ Inject one valid and one malformed tool call, see only the valid survive
Valid tool calls after filtering:
  - get_weather({'city': 'Vienna'})  [id=call_1]

The malformed second call (missing id, non-JSON args) is dropped before reaching your handler.

$ The malformed call that used to crash loops in 1.4.2
malformed.tool_calls = [
  {"name": "get_weather", "args": {"city": "Vienna"}, "id": "call_1"},
  {"name": "get_weather", "args": "not-json", "id": None},  # dropped in 1.4.3
]

Common flags

#39366
fix: filter invalid tool calls from model content.
bind_tools
Attaches a tool schema so the model can emit tool calls.
ToolNode
Executes tool calls in an agent graph, consuming the filtered list.

History

Trust but verify

LLMs are probabilistic, so their tool calls occasionally deviate from the schema - a dropped id, a non-JSON argument blob. LangChain initially forwarded these verbatim, treating the model as always-correct. The 1.4.3 fix adds a verification pass in the Responses-API converter, adopting the \u201ctrust but verify\u201d posture that production agents need.

Fun facts

Pros & cons

pros

  • + No more crash-on-garbage
  • + Cleaner agent loops
  • + Intermittent bugs removed for free

cons

  • − Dropped calls are not retried automatically
  • − You still validate at the boundary you trust

Takeaways

  1. 1Upgrade to langchain-openai>=1.4.3.
  2. 2Trust the filtered tool_calls but keep a boundary backstop.
  3. 3Log dropped calls if you want visibility into model drift.

Related commands

← all learning