langchain-ai/langchain · error · ValueError
'token_counter' expected to be a model that implements 'get_
Error message
'token_counter' expected to be a model that implements 'get_num_tokens_from_messages()' or a function. Received object of type {type(actual_token_counter)}. What it means
Raised by `trim_messages` when `token_counter` is neither a string shortcut, an object exposing `get_num_tokens_from_messages`, nor a callable. The function must be able to derive a per-message/per-list token count, so opaque objects of any other type are rejected.
Source
Thrown at libs/core/langchain_core/messages/utils.py:1489
if (
next(
iter(inspect.signature(actual_token_counter).parameters.values())
).annotation
is BaseMessage
):
def list_token_counter(messages: Sequence[BaseMessage]) -> int:
return sum(actual_token_counter(msg) for msg in messages) # type: ignore[arg-type, misc]
else:
list_token_counter = actual_token_counter
else:
msg = ( # type: ignore[unreachable]
f"'token_counter' expected to be a model that implements "
f"'get_num_tokens_from_messages()' or a function. Received object of type "
f"{type(actual_token_counter)}."
)
raise ValueError(msg)
text_splitter_fn: Callable[[str], list[str]]
if _HAS_LANGCHAIN_TEXT_SPLITTERS and isinstance(text_splitter, TextSplitter):
text_splitter_fn = text_splitter.split_text
elif text_splitter:
text_splitter_fn = cast("Callable[[str], list[str]]", text_splitter)
else:
text_splitter_fn = _default_text_splitter
if strategy == "first":
return _first_max_tokens(
messages,
max_tokens=max_tokens,
token_counter=list_token_counter,
text_splitter=text_splitter_fn,
partial_strategy="first" if allow_partial else None,
end_on=end_on,
)View on GitHub (pinned to e32fa9a52e)
Solutions
- Pass a real language-model instance (it implements `get_num_tokens_from_messages`)
- Or pass a plain callable such as `len`, a tokenizer wrapper, or `lambda msgs: sum(count_tokens(m.content) for m in msgs)`
- If the counter is optional, only pass it when it is not None
Example fix
# before
trim_messages(msgs, max_tokens=500, token_counter={'model': 'gpt-4o'})
# after
trim_messages(msgs, max_tokens=500, token_counter=len) Defensive patterns
Strategy: type-guard
Validate before calling
def usable_token_counter(tc) -> bool:
return callable(tc) or hasattr(tc, 'get_num_tokens_from_messages')
assert usable_token_counter(token_counter), 'token_counter must be a model instance or callable' Type guard
def is_token_counter(tc: object) -> bool:
return callable(tc) or hasattr(tc, 'get_num_tokens_from_messages') Prevention
- Pass model instances, not classes or config dicts
- Fall back to `len` as a cheap deterministic counter in tests
- Guard optional counters: only pass when not None
When it happens
Trigger: Passing an uninitialized model class (not an instance), a tokenizer config dict, a string name object, or some other non-callable as `token_counter`.
Common situations: Passing the class instead of the instance (`token_counter=BaseLanguageModel` subclass); passing a serialized model config; a variable that is None after a failed initialization.
Related errors
- Invalid token_counter shortcut '{token_counter}'. Available
- start_on parameter is only valid with strategy='last'
- include_system parameter is only valid with strategy='last'
- Unrecognized {strategy=}. Supported strategies are 'last' an
- Unrecognized format={format!r}. Supported formats are 'prefi
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/8d4c2b7fa9e5ec60.
Report an issue: GitHub.