Skip to content

trim_messages breaks when token_counter is a per-message callable (lambda, subclass annotation, or postponed annotations) #35629

@gautamvarmadatla

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

No response

Reproduction Steps / Example Code (Python)

from __future__ import annotations
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
from langchain_core.messages.utils import trim_messages

messages = [
    HumanMessage("What is 2 + 2?"),
    AIMessage("It is 4."),
    HumanMessage("What about 3 + 3?"),
]

def run_case(name, counter):
    try:
        result = trim_messages(messages, max_tokens=5, token_counter=counter)
        print(f"{name}: UNEXPECTED SUCCESS — returned {result}")
    except Exception as e:
        print(f"{name}: FAIL — {type(e).__name__}: {e}")

# Case 1: lambda — lambdas cannot be annotated
run_case("lambda", lambda msg: len(msg.content.split()))

# Case 2: no annotation
def counter_no_annotation(msg):
    return len(msg.content.split())

run_case("no annotation", counter_no_annotation)

# Case 3: string annotation
def counter_string_annotation(msg: "BaseMessage") -> int:
    return len(msg.content.split())

run_case("string annotation", counter_string_annotation)


# Case 4: subclass annotation
def counter_subclass(msg: HumanMessage) -> int:
    return len(msg.content.split())

run_case("subclass annotation", counter_subclass)


# Case 5: postponed annotations via `from __future__ import annotations`
def counter_postponed(msg: BaseMessage) -> int:
    return len(msg.content.split())

run_case("postponed annotations", counter_postponed)

Error Message and Stack Trace (if applicable)

lambda: FAIL — AttributeError: 'list' object has no attribute 'content'
no annotation: FAIL — AttributeError: 'list' object has no attribute 'content'
string annotation: FAIL — AttributeError: 'list' object has no attribute 'content'
subclass annotation: FAIL — AttributeError: 'list' object has no attribute 'content'
postponed annotations: FAIL — AttributeError: 'list' object has no attribute 'content'

Description

trim_messages accepts token_counter as either a per-list (messages: list[BaseMessage]) -> int or per-message (msg: BaseMessage) -> int callable, but the per-message form is misdetected in many natural cases.

The current detection logic relies on a raw annotation identity check against BaseMessage, which fails for common cases such as lambdas, unannotated functions, string annotations, subclass annotations, and postponed annotations. In these cases, the callable is misclassified as a list counter and called with a list of messages, which commonly causes runtime errors such as AttributeError: 'list' object has no attribute 'content'.

System Info

System Information

OS: Windows
OS Version: 10.0.26100
Python Version: 3.13.7 (tags/v3.13.7:bcee1c3, Aug 14 2025, 14:15:11) [MSC v.1944 64 bit (AMD64)]

Package Information

langchain_core: 1.2.17
langsmith: 0.7.9
langchain_tests: 1.1.5

Optional packages not installed

deepagents
deepagents-cli

Other Dependencies

httpx: 0.28.1
jsonpatch: 1.33
numpy: 2.3.5
orjson: 3.11.5
packaging: 26.0
pydantic: 2.12.5
pytest: 9.0.2
pytest-asyncio: 1.3.0
pytest-benchmark: 5.2.3
pytest-codspeed: 4.3.0
pytest-recording: 0.13.4
pytest-socket: 0.7.0
pyyaml: 6.0.3
requests: 2.32.5
requests-toolbelt: 1.0.0
rich: 14.2.0
syrupy: 5.1.0
tenacity: 9.1.4
typing-extensions: 4.15.0
uuid-utils: 0.14.1
vcrpy: 8.1.1
wrapt: 2.0.1
xxhash: 3.6.0
zstandard: 0.25.0

Metadata

Metadata

Labels

bugRelated to a bug, vulnerability, unexpected error with an existing featurecore`langchain-core` package issues & PRsexternal

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions