langchain - 💡(How to fix) Fix ChatAnthropic.bind_tools mutates caller-provided tool_choice dict

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…

When ChatAnthropic.bind_tools receives tool_choice as a dict and parallel_tool_calls is set, it stores the caller-provided dict directly in kwargs["tool_choice"], then adds disable_parallel_tool_use to it.

This mutates the original tool_choice object passed by the caller. If the same dict is reused across calls, the disable_parallel_tool_use option can leak into later calls unexpectedly.

A minimal fix would be to copy the tool_choice dict before adding disable_parallel_tool_use, preserving the existing Anthropic wire payload while avoiding mutation of caller-owned input. I’d also add a focused unit test covering the no-mutation behavior.

Would this be an acceptable scoped fix? If so, could you please assign this to me?

Error Message

No exception is raised. The issue is that tool_choice is mutated in place:

{ "type": "tool", "name": "GetWeather", "disable_parallel_tool_use": True, }

Root Cause

When ChatAnthropic.bind_tools receives tool_choice as a dict and parallel_tool_calls is set, it stores the caller-provided dict directly in kwargs["tool_choice"], then adds disable_parallel_tool_use to it.

This mutates the original tool_choice object passed by the caller. If the same dict is reused across calls, the disable_parallel_tool_use option can leak into later calls unexpectedly.

A minimal fix would be to copy the tool_choice dict before adding disable_parallel_tool_use, preserving the existing Anthropic wire payload while avoiding mutation of caller-owned input. I’d also add a focused unit test covering the no-mutation behavior.

Would this be an acceptable scoped fix? If so, could you please assign this to me?

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.

Other Dependencies

httpx: 0.28.1 jsonpatch: 1.33 orjson: 3.11.8 packaging: 24.2 pydantic: 2.12.5 pytest: 8.4.2 pyyaml: 5.4.1 requests: 2.32.5 requests-toolbelt: 1.0.0 tenacity: 9.1.2 typing-extensions: 4.15.0 uuid-utils: 0.14.1 websockets: 16.0 wrapt: 1.17.2 xxhash: 3.5.0 zstandard: 0.25.0

Code Example

from langchain_anthropic import ChatAnthropic

tool_choice = {"type": "tool", "name": "GetWeather"}

model = ChatAnthropic(model="claude-sonnet-4-5-20250929")

model.bind_tools(
    tools=[
        {
            "name": "GetWeather",
            "description": "Get weather",
            "input_schema": {"type": "object", "properties": {}},
        }
    ],
    tool_choice=tool_choice,
    parallel_tool_calls=False,
)

assert tool_choice == {"type": "tool", "name": "GetWeather"}

---

No exception is raised. The issue is that tool_choice is mutated in place:

{
    "type": "tool",
    "name": "GetWeather",
    "disable_parallel_tool_use": True,
}
RAW_BUFFERClick to expand / collapse

Submission checklist

  • 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

I did not find an existing open issue or PR specifically about ChatAnthropic.bind_tools mutating a caller-provided tool_choice dict.

Reproduction Steps / Example Code (Python)

from langchain_anthropic import ChatAnthropic

tool_choice = {"type": "tool", "name": "GetWeather"}

model = ChatAnthropic(model="claude-sonnet-4-5-20250929")

model.bind_tools(
    tools=[
        {
            "name": "GetWeather",
            "description": "Get weather",
            "input_schema": {"type": "object", "properties": {}},
        }
    ],
    tool_choice=tool_choice,
    parallel_tool_calls=False,
)

assert tool_choice == {"type": "tool", "name": "GetWeather"}

Error Message and Stack Trace (if applicable)

No exception is raised. The issue is that tool_choice is mutated in place:

{
    "type": "tool",
    "name": "GetWeather",
    "disable_parallel_tool_use": True,
}

Description

When ChatAnthropic.bind_tools receives tool_choice as a dict and parallel_tool_calls is set, it stores the caller-provided dict directly in kwargs["tool_choice"], then adds disable_parallel_tool_use to it.

This mutates the original tool_choice object passed by the caller. If the same dict is reused across calls, the disable_parallel_tool_use option can leak into later calls unexpectedly.

A minimal fix would be to copy the tool_choice dict before adding disable_parallel_tool_use, preserving the existing Anthropic wire payload while avoiding mutation of caller-owned input. I’d also add a focused unit test covering the no-mutation behavior.

Would this be an acceptable scoped fix? If so, could you please assign this to me?

System Info

System Information

OS: Linux OS Version: #1 SMP PREEMPT_DYNAMIC Mon Dec 1 20:46:23 UTC 2025 Python Version: 3.10.12 (main, Mar 3 2026, 11:56:32) [GCC 11.4.0]

Package Information

langchain_core: 1.3.3 langsmith: 0.8.1 langchain_protocol: 0.0.15 langgraph_sdk: 0.3.14

Optional packages not installed

deepagents deepagents-cli

Other Dependencies

httpx: 0.28.1 jsonpatch: 1.33 orjson: 3.11.8 packaging: 24.2 pydantic: 2.12.5 pytest: 8.4.2 pyyaml: 5.4.1 requests: 2.32.5 requests-toolbelt: 1.0.0 tenacity: 9.1.2 typing-extensions: 4.15.0 uuid-utils: 0.14.1 websockets: 16.0 wrapt: 1.17.2 xxhash: 3.5.0 zstandard: 0.25.0

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