{"record":{"id":"8d4c2b7fa9e5ec60","repo":"langchain-ai/langchain","slug":"token-counter-expected-to-be-a-model-that-implem","errorCode":null,"errorMessage":"'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)}.","messagePattern":"'token_counter' expected to be a model that implements 'get_num_tokens_from_messages\\(\\)' or a function\\. Received object of type (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/messages/utils.py","lineNumber":1489,"sourceCode":"        if (\n            next(\n                iter(inspect.signature(actual_token_counter).parameters.values())\n            ).annotation\n            is BaseMessage\n        ):\n\n            def list_token_counter(messages: Sequence[BaseMessage]) -> int:\n                return sum(actual_token_counter(msg) for msg in messages)  # type: ignore[arg-type, misc]\n\n        else:\n            list_token_counter = actual_token_counter\n    else:\n        msg = (  # type: ignore[unreachable]\n            f\"'token_counter' expected to be a model that implements \"\n            f\"'get_num_tokens_from_messages()' or a function. Received object of type \"\n            f\"{type(actual_token_counter)}.\"\n        )\n        raise ValueError(msg)\n\n    text_splitter_fn: Callable[[str], list[str]]\n    if _HAS_LANGCHAIN_TEXT_SPLITTERS and isinstance(text_splitter, TextSplitter):\n        text_splitter_fn = text_splitter.split_text\n    elif text_splitter:\n        text_splitter_fn = cast(\"Callable[[str], list[str]]\", text_splitter)\n    else:\n        text_splitter_fn = _default_text_splitter\n\n    if strategy == \"first\":\n        return _first_max_tokens(\n            messages,\n            max_tokens=max_tokens,\n            token_counter=list_token_counter,\n            text_splitter=text_splitter_fn,\n            partial_strategy=\"first\" if allow_partial else None,\n            end_on=end_on,\n        )","sourceCodeStart":1471,"sourceCodeEnd":1507,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/messages/utils.py#L1471-L1507","documentation":"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.","triggerScenarios":"Passing an uninitialized model class (not an instance), a tokenizer config dict, a string name object, or some other non-callable as `token_counter`.","commonSituations":"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.","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"],"exampleFix":"# before\ntrim_messages(msgs, max_tokens=500, token_counter={'model': 'gpt-4o'})\n\n# after\ntrim_messages(msgs, max_tokens=500, token_counter=len)","handlingStrategy":"type-guard","validationCode":"def usable_token_counter(tc) -> bool:\n    return callable(tc) or hasattr(tc, 'get_num_tokens_from_messages')\n\nassert usable_token_counter(token_counter), 'token_counter must be a model instance or callable'","typeGuard":"def is_token_counter(tc: object) -> bool:\n    return callable(tc) or hasattr(tc, 'get_num_tokens_from_messages')","tryCatchPattern":null,"preventionTips":["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"],"tags":["trim-messages","token-counting","argument-validation"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}