-
Notifications
You must be signed in to change notification settings - Fork 21k
Description
Checked other resources
- This is a bug, not a usage question.
- I added a clear and descriptive title that summarizes this issue.
- I used the GitHub search to find a similar question and didn't find it.
- I am sure that this is a bug in LangChain rather than my code.
- The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
- This is not related to the langchain-community package.
- I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.
Package (Required)
- langchain
- langchain-openai
- langchain-anthropic
- langchain-classic
- langchain-core
- langchain-model-profiles
- langchain-tests
- langchain-text-splitters
- langchain-chroma
- langchain-deepseek
- langchain-exa
- langchain-fireworks
- langchain-groq
- langchain-huggingface
- langchain-mistralai
- langchain-nomic
- langchain-ollama
- langchain-openrouter
- langchain-perplexity
- langchain-qdrant
- langchain-xai
- Other / not sure / general
Related Issues / PRs
#32562, #30563, #32016, langchain-ai/langchainjs#8394
Reproduction Steps / Example Code (Python)
import os
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain.tools import tool
@tool
def my_tool(url: str) -> str:
"""Fetch data from the given URL."""
return f"Fetched: {url}"
llm = ChatOpenAI(
model="deepseek/deepseek-v3.2",
api_key=os.environ.get("OPENROUTER_API_KEY"),
base_url="https://openrouter.ai/api/v1",
)
agent = create_agent(
model=llm,
tools=[my_tool],
system_prompt="You are a helpful assistant.",
)
import asyncio
async def main():
async for stream_mode, data in agent.astream(
{"messages": [{"role": "user", "content": 'Use my_tool with "http://mywebsite.com"'}]},
stream_mode=["messages", "updates"],
):
if stream_mode == "messages":
token, metadata = data
if hasattr(token, 'tool_call_chunks') and token.tool_call_chunks:
for tc in token.tool_call_chunks:
print(f"[TOOL_CHUNK] name={tc.get('name')} args={tc.get('args')!r} id={tc.get('id')}")
if hasattr(token, 'tool_calls') and token.tool_calls:
for tc in token.tool_calls:
print(f"[TOOL_CALL_PARSED] name={tc.get('name')} args={tc.get('args')}")
asyncio.run(main())Error Message and Stack Trace (if applicable)
ToolException: Error executing tool my_tool: 1 validation error for my_toolArguments
url
Field required [type=missing, input_value={}, input_type=dict]
at langgraph/prebuilt/tool_node.py
at langchain_core/tools/base.pyDescription
When streaming tool calls via OpenRouter (tested with deepseek/deepseek-v3.2), the agent executes tools with empty args {}, causing Field required validation errors. The root cause is that OpenRouter's upstream providers fragment tool call arguments across multiple SSE chunks, and langchain parses the first empty chunk as a valid tool call.
Instrumented streaming output showing the problem:
[TOOL_CHUNK] name=my_tool args='' id=call_34db6a0a9d314d71a8a74b3d
[TOOL_CALL_PARSED] name=my_tool args={} ← parsed as valid, tool executed with empty args
[TOOL_CHUNK] name= args='{' id=
[TOOL_CHUNK] name= args='"url": "http://mywebsite.com"' id=
[TOOL_CHUNK] name= args='}' id=
The first chunk arrives with name="my_tool" and args="". parse_partial_json("") returns {} — a valid but empty dict. The ToolNode executes the tool immediately with these empty args. The subsequent chunks containing the actual arguments arrive too late.
This fragmentation is common across providers. I tested all 8 upstream providers available for this model on OpenRouter. Most exhibit this pattern, with varying frequency. The failure rate in production depends on which provider OpenRouter routes to and timing conditions.
When the agent encounters the error, it often retries the tool call in a loop, generating the same fragmented pattern repeatedly until hitting the recursion limit.
JS-side fix exists: This is the same root cause reported and fixed on the JS side in langchain-ai/langchainjs#8394 (PR langchain-ai/langchainjs#8419). The fix concatenates all tool_call_chunks belonging to the same tool call before parsing. As far as I can tell, this hasn't been ported to the Python side.
Workaround: Setting streaming=False on ChatOpenAI reliably resolves the issue.
System Info
System Information
OS: Linux
OS Version: Ubuntu 22.04
Python Version: 3.12.3
Package Information
langchain_core: 1.2.14
langchain: 1.2.10
langchain_openai: 1.1.10
langgraph: 1.0.9
Other Dependencies
openai: 2.21.0
pydantic: 2.12.5
httpx: 0.28.1