langchain - ✅(Solved) Fix openai: malformed tool calls cause all tool calls to be silently dropped [3 pull requests, 4 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#35782Fetched 2026-04-08 00:24:35
View on GitHub
Comments
4
Participants
3
Timeline
12
Reactions
0
Author
Timeline (top)
commented ×4labeled ×3cross-referenced ×2referenced ×2

What I'm doing: Processing streaming chat responses that include tool calls from OpenAI-compatible APIs.

Expected behavior: When one tool call in a batch is malformed (missing required 'function' key), the valid tool calls should still be processed. The malformed one should be skipped or logged, but valid tool calls should not be lost.

Actual behavior: A bare except KeyError: pass in _convert_delta_to_message_chunk causes the entire list comprehension to fail, silently dropping ALL tool calls when ANY single tool call is malformed.

Root Cause: In libs/partners/openai/langchain_openai/chat_models/base.py, lines 417-429:

if raw_tool_calls := _dict.get("tool_calls"):
    try:
        tool_call_chunks = [
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
            for rtc in raw_tool_calls
        ]
    except KeyError:
        pass  # BUG: This silently drops ALL tool calls

The except KeyError: pass wraps the entire list comprehension. When any single tool call lacks the 'function' or 'index' keys, the entire batch is discarded without warning.

Impact:

  • Silent data loss in streaming responses
  • Difficult to debug since no error is raised
  • Affects all OpenAI-compatible integrations

Suggested Fix: Handle errors per-tool-call rather than for the entire batch:

tool_call_chunks = []
for rtc in raw_tool_calls:
    try:
        tool_call_chunks.append(
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
        )
    except KeyError:
        # Log warning or skip silently per-tool-call
        continue

I am willing to submit a PR to fix this issue. Please assign this issue to me. I have already identified the root cause and can implement the fix as suggested above.

Error Message

No exception is raised - this is a silent data loss bug.

Output from reproduction script: ✓ Test 1 passed: Normal tool call works correctly ✓ Test 2 passed (bug confirmed): Malformed tool call was silently dropped Tool call chunks count: 0 ✗ BUG CONFIRMED: ALL tool calls were dropped due to one malformed tool call! Expected: 1 valid tool call chunk Actual: 0 tool call chunks (entire batch lost)

Root Cause

Root Cause: In libs/partners/openai/langchain_openai/chat_models/base.py, lines 417-429:

Fix Action

Fix / Workaround

  • 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.

PR fix notes

PR #35813: fix(openai): skip malformed tool call chunks instead of dropping entire batch

Description (problem / solution / changelog)

Summary

  • Fixes #35782
  • In _convert_delta_to_message_chunk, a try/except KeyError: pass wrapped the entire list comprehension for tool call chunks. If any single item in raw_tool_calls was missing the function or index key, the whole batch was silently discarded.
  • Move the try/except inside the loop so only the malformed item is skipped — valid siblings are preserved.

Root cause

# before: one bad item drops everything
try:
    tool_call_chunks = [tool_call_chunk(...) for rtc in raw_tool_calls]
except KeyError:
    pass  # entire batch lost
# after: bad items are skipped individually
for rtc in raw_tool_calls:
    try:
        tool_call_chunks.append(tool_call_chunk(...))
    except KeyError:
        pass  # only this item skipped

Tests

Two new unit tests in test_base.py:

  • test__convert_delta_to_message_chunk_malformed_tool_call — confirms the valid chunk survives when a sibling is missing function
  • test__convert_delta_to_message_chunk_all_valid_tool_calls — confirms all chunks are returned when none are malformed

Areas requiring careful review

The except KeyError: pass behavior is intentional for genuinely incomplete streaming deltas (e.g. the first chunk may arrive with only index and no function yet). The per-item handling preserves that: a delta with only one incomplete item no longer poisons the rest.


This PR was developed with the assistance of an AI agent (Claude Sonnet 4.6).

Changed files

  • libs/core/langchain_core/runnables/retry.py (modified, +8/-2)
  • libs/core/tests/unit_tests/runnables/test_runnable.py (modified, +146/-0)
  • libs/langchain_v1/langchain/agents/middleware/tool_selection.py (modified, +18/-5)
  • libs/langchain_v1/tests/unit_tests/agents/middleware/implementations/test_tool_selection.py (modified, +80/-0)
  • libs/partners/openai/langchain_openai/chat_models/base.py (modified, +11/-11)
  • libs/partners/openai/tests/unit_tests/chat_models/test_base.py (modified, +62/-0)
  • libs/text-splitters/langchain_text_splitters/konlpy.py (modified, +7/-13)
  • libs/text-splitters/langchain_text_splitters/nltk.py (modified, +4/-9)
  • libs/text-splitters/langchain_text_splitters/sentence_transformers.py (modified, +7/-12)
  • libs/text-splitters/langchain_text_splitters/spacy.py (modified, +12/-15)
  • libs/text-splitters/tests/unit_tests/test_text_splitters.py (modified, +20/-0)

PR #417: feat(nodes): add llm_vision_ollama node for open-source image-to-text

Description (problem / solution / changelog)

Summary

Implements a new vision node that uses locally-hosted open-source multimodal models via Ollama as an alternative to proprietary vision APIs. Supports LLaVA, Llama 3.2 Vision, Moondream, MiniCPM-V, and Qwen 2.5 VL models (10 pre-configured profiles). No API key required — runs fully on-premise.

Type

feat

Testing

  • Tests added or updated
  • Tested locally
  • ./builder test passes

Checklist

  • Commit messages follow conventional commits
  • No secrets or credentials included
  • Wiki updated (if applicable)
  • Breaking changes documented (if applicable)

Linked Issue

<!-- REQUIRED: Every PR must be linked to an issue. Use one of: --> <!-- Fixes #123 / Closes #123 / Resolves #123 -->

Fixes #393

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

Summary by CodeRabbit

  • New Features

    • Ollama Vision node for image-to-text analysis using local vision-capable models.
    • Supports chunked image uploads, automatic image encoding, and streaming image handling.
    • Many pre-configured model profiles plus a customizable profile.
  • Improvements

    • UI exposes vision system/prompt editing, model selection, and local server settings.
    • More robust LLM calls with retries and clearer, user-friendly error messages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Changed files

  • nodes/src/nodes/llm_vision_ollama/IGlobal.py (added, +48/-0)
  • nodes/src/nodes/llm_vision_ollama/IInstance.py (added, +81/-0)
  • nodes/src/nodes/llm_vision_ollama/__init__.py (added, +39/-0)
  • nodes/src/nodes/llm_vision_ollama/ollama_vision.py (added, +133/-0)
  • nodes/src/nodes/llm_vision_ollama/requirements.txt (added, +9/-0)
  • nodes/src/nodes/llm_vision_ollama/services.json (added, +390/-0)

PR #36662: fix(openai): handle malformed tool calls per-item instead of per-batch

Description (problem / solution / changelog)

Summary

Fixes #35782

  • The _convert_delta_to_message_chunk function wrapped an entire list comprehension in a single try/except KeyError: pass block. If any tool call chunk in a streaming batch was malformed (e.g., missing "function" key), all tool call chunks — including valid ones — were silently dropped.
  • This PR restructures the loop so each tool call chunk is processed independently: a KeyError in one item skips only that item, preserving all valid tool calls in the batch.
  • Added a unit test (test_convert_delta_to_message_chunk_mixed_tool_calls) that verifies mixed valid/invalid tool call entries are handled correctly.

Areas requiring careful review

  • The change is in libs/partners/openai/langchain_openai/chat_models/base.py around line 417. The logic is intentionally kept minimal — only the try/except scope was narrowed.

Test plan

  • New unit test passes with mixed valid/invalid tool call chunks
  • Full test suite passes (318 tests)
  • Lint and mypy pass

This PR was developed with the assistance of an AI coding agent.

🤖 Generated with Claude Code

Changed files

  • libs/partners/openai/langchain_openai/chat_models/base.py (modified, +12/-12)
  • libs/partners/openai/tests/unit_tests/chat_models/test_base.py (modified, +30/-0)
  • libs/partners/openai/uv.lock (modified, +3/-2)

Code Example

#!/usr/bin/env python3
"""
Minimal reproduction for: malformed tool calls cause all tool calls to be silently dropped

This script demonstrates a bug in _convert_delta_to_message_chunk where a malformed
tool call (missing 'function' key) causes ALL tool calls in the batch to be silently dropped.
"""

from langchain_openai.chat_models.base import _convert_delta_to_message_chunk


# Test case: One malformed tool call in a batch causes ALL to be dropped
mixed_delta = {
    "role": "assistant",
    "content": None,
    "tool_calls": [
        {
            "id": "call_good",
            "type": "function", 
            "function": {"name": "good_func", "arguments": "{}"},
            "index": 0
        },
        {
            "id": "call_bad",
            "type": "function",
            # Missing 'function' key - causes KeyError
            "index": 1
        }
    ]
}

result = _convert_delta_to_message_chunk(mixed_delta, None)
print(f"Tool call chunks count: {len(result.tool_call_chunks)}")
# Expected: 1 valid tool call chunk (the good one)
# Actual: 0 tool call chunks (entire batch lost!)

---

No exception is raised - this is a silent data loss bug.

Output from reproduction script:
Test 1 passed: Normal tool call works correctly
Test 2 passed (bug confirmed): Malformed tool call was silently dropped
Tool call chunks count: 0
BUG CONFIRMED: ALL tool calls were dropped due to one malformed tool call!
  Expected: 1 valid tool call chunk
  Actual: 0 tool call chunks (entire batch lost)

---

if raw_tool_calls := _dict.get("tool_calls"):
    try:
        tool_call_chunks = [
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
            for rtc in raw_tool_calls
        ]
    except KeyError:
        pass  # BUG: This silently drops ALL tool calls

---

tool_call_chunks = []
for rtc in raw_tool_calls:
    try:
        tool_call_chunks.append(
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
        )
    except KeyError:
        # Log warning or skip silently per-tool-call
        continue

---

Repository: langchain-ai/langchain
Branch: master
Commit: 1891d414be
Commit Date: 2026-03-11 23:09:17 -0400
langchain-openai version (from pyproject.toml): 1.1.11
langchain-core version (from pyproject.toml): 1.2.18
Python version: 3.10.12
RAW_BUFFERClick to expand / collapse

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

  • langchain-openai

Reproduction Steps / Example Code (Python)

#!/usr/bin/env python3
"""
Minimal reproduction for: malformed tool calls cause all tool calls to be silently dropped

This script demonstrates a bug in _convert_delta_to_message_chunk where a malformed
tool call (missing 'function' key) causes ALL tool calls in the batch to be silently dropped.
"""

from langchain_openai.chat_models.base import _convert_delta_to_message_chunk


# Test case: One malformed tool call in a batch causes ALL to be dropped
mixed_delta = {
    "role": "assistant",
    "content": None,
    "tool_calls": [
        {
            "id": "call_good",
            "type": "function", 
            "function": {"name": "good_func", "arguments": "{}"},
            "index": 0
        },
        {
            "id": "call_bad",
            "type": "function",
            # Missing 'function' key - causes KeyError
            "index": 1
        }
    ]
}

result = _convert_delta_to_message_chunk(mixed_delta, None)
print(f"Tool call chunks count: {len(result.tool_call_chunks)}")
# Expected: 1 valid tool call chunk (the good one)
# Actual: 0 tool call chunks (entire batch lost!)

Error Message and Stack Trace

No exception is raised - this is a silent data loss bug.

Output from reproduction script:
✓ Test 1 passed: Normal tool call works correctly
✓ Test 2 passed (bug confirmed): Malformed tool call was silently dropped
Tool call chunks count: 0
✗ BUG CONFIRMED: ALL tool calls were dropped due to one malformed tool call!
  Expected: 1 valid tool call chunk
  Actual: 0 tool call chunks (entire batch lost)

Description

What I'm doing: Processing streaming chat responses that include tool calls from OpenAI-compatible APIs.

Expected behavior: When one tool call in a batch is malformed (missing required 'function' key), the valid tool calls should still be processed. The malformed one should be skipped or logged, but valid tool calls should not be lost.

Actual behavior: A bare except KeyError: pass in _convert_delta_to_message_chunk causes the entire list comprehension to fail, silently dropping ALL tool calls when ANY single tool call is malformed.

Root Cause: In libs/partners/openai/langchain_openai/chat_models/base.py, lines 417-429:

if raw_tool_calls := _dict.get("tool_calls"):
    try:
        tool_call_chunks = [
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
            for rtc in raw_tool_calls
        ]
    except KeyError:
        pass  # BUG: This silently drops ALL tool calls

The except KeyError: pass wraps the entire list comprehension. When any single tool call lacks the 'function' or 'index' keys, the entire batch is discarded without warning.

Impact:

  • Silent data loss in streaming responses
  • Difficult to debug since no error is raised
  • Affects all OpenAI-compatible integrations

Suggested Fix: Handle errors per-tool-call rather than for the entire batch:

tool_call_chunks = []
for rtc in raw_tool_calls:
    try:
        tool_call_chunks.append(
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
        )
    except KeyError:
        # Log warning or skip silently per-tool-call
        continue

I am willing to submit a PR to fix this issue. Please assign this issue to me. I have already identified the root cause and can implement the fix as suggested above.

System Info

Repository: langchain-ai/langchain
Branch: master
Commit: 1891d414be
Commit Date: 2026-03-11 23:09:17 -0400
langchain-openai version (from pyproject.toml): 1.1.11
langchain-core version (from pyproject.toml): 1.2.18
Python version: 3.10.12

Note: This issue was discovered using automated static analysis and confirmed through dynamic testing. The reproduction script confirms the bug exists in the current codebase.

extent analysis

Fix Plan

Step 1: Update _convert_delta_to_message_chunk to handle errors per-tool-call

Replace the existing list comprehension with a for loop to handle errors per-tool-call:

tool_call_chunks = []
for rtc in raw_tool_calls:
    try:
        tool_call_chunks.append(
            tool_call_chunk(
                name=rtc["function"].get("name"),
                args=rtc["function"].get("arguments"),
                id=rtc.get("id"),
                index=rtc["index"],
            )
        )
    except KeyError as e:
        # Log warning or skip silently per-tool-call
        print(f"Warning: Skipping tool call with missing key: {e}")

Step 2: Update the try block to handle potential KeyError exceptions

In the try block, add a check to ensure that the required keys exist before attempting to access them:

try:
    tool_call_chunks.append(
        tool_call_chunk(
            name=rtc.get("function", {}).get("name"),
            args=rtc.get("function", {}).get("arguments"),
            id=rtc.get("id"),
            index=rtc.get("index"),
        )
    )
except KeyError as e:
    # Log warning or skip silently per-tool-call
    print(f"Warning: Skipping tool call with missing key: {e}")

Step 3: Test the updated code

Run the reproduction script with the updated code to verify that the fix works as expected.

Step 4: Submit a PR to fix the issue

Once the fix is verified, submit a PR to the LangChain repository with the updated code.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING