Skip to content

langchain-anthropic: cache_control on a tool_use content block is silently dropped when a matching tool_calls item exists #38398

Description

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

No response

Reproduction Steps / Example Code (Python)

from langchain_core.messages import AIMessage, HumanMessage, ToolCall
from langchain_anthropic.chat_models import _format_messages

ai = AIMessage(
    content=[
        {"type": "text", "text": "Let me check."},
        {
            "type": "tool_use",
            "id": "toolu_1",
            "name": "get_weather",
            "input": {"city": "Paris"},
            "cache_control": {"type": "ephemeral"},  # breakpoint on the tool_use block
        },
    ],
    tool_calls=[ToolCall(name="get_weather", args={"city": "Paris"}, id="toolu_1")],
)

_, formatted = _format_messages([HumanMessage(content="weather?"), ai])
out = formatted[-1]["content"]

print(out)  # cache_control is gone
# [{'type': 'text', 'text': 'Let me check.'}, {'type': 'tool_use', 'name': 'get_weather', 'input': {'city': 'Paris'}, 'id': 'toolu_1'}]

assert any("cache_control" in b for b in out), "cache_control was silently dropped"

Error Message and Stack Trace (if applicable)

Description

When an AIMessage carries a tool call in both its content (as a tool_use block) and the structured tool_calls field, _format_messages rebuilds the tool_use block from tool_calls ("the tool_call is preferred") and discards every extra key on the original block, including cache_control.
As a result, a prompt-cache breakpoint placed on a tool_use block is silently lost during conversion.

A provider-returned assistant turn that makes a tool call typically ends with the tool_use block. Any caller doing manual prompt-cache breakpoint placement on the conversation (rather than relying on a middleware) cannot put a surviving breakpoint on such a turn.

This is inconsistent with the rest of _format_messages: the text, thinking, and server_tool_use/mcp_tool_use branches all explicitly preserve cache_control. tool_use is the only content block type that drops it.

System Info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:15 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6041
Python Version: 3.14.2 (main, Dec 5 2025, 21:11:58) [Clang 21.1.4 ]

Package Information

langchain_core: 1.4.8
langsmith: 0.9.1
langchain_anthropic: 1.4.7
langchain_protocol: 0.0.18

Optional packages not installed

deepagents
deepagents-cli

Other Dependencies

anthropic: 0.111.0
anyio: 4.14.0
distro: 1.9.0
httpx: 0.28.1
jsonpatch: 1.33
orjson: 3.11.9
packaging: 26.2
pydantic: 2.13.4
pyyaml: 6.0.3
requests: 2.34.2
requests-toolbelt: 1.0.0
sniffio: 1.3.1
tenacity: 9.1.4
typing-extensions: 4.15.0
uuid-utils: 0.16.2
websockets: 16.0
xxhash: 3.7.1
zstandard: 0.25.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    anthropic`langchain-anthropic` package issues & PRsbugRelated to a bug, vulnerability, unexpected error with an existing featureexternal

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions