headroomlabs-ai/headroom · warning · NotImplementedError
{self.__class__.__name__} does not support decoding
Error message
{self.__class__.__name__} does not support decoding What it means
BaseTokenizer.decode() is optional: the base-class default raises NotImplementedError naming the subclass, because not every backend can map token IDs back to text. Estimating/heuristic counters only approximate counts and carry no vocabulary, so decode is impossible.
Source
Thrown at headroom/tokenizers/base.py:458
"""
raise NotImplementedError(f"{self.__class__.__name__} does not support encoding")
def decode(self, tokens: list[int]) -> str:
"""Decode token IDs to text.
Optional method - not all backends support decoding.
Default implementation raises NotImplementedError.
Args:
tokens: List of token IDs.
Returns:
Decoded text.
Raises:
NotImplementedError: If decoding is not supported.
"""
raise NotImplementedError(f"{self.__class__.__name__} does not support decoding")
class _DelegatingBlockCounter(BaseTokenizer):
"""Adapter exposing :meth:`BaseTokenizer._count_content_parts` to non-subclasses.
The provider token counters in ``headroom/providers/`` are not
``BaseTokenizer`` subclasses, and each grew its own shortened content-block
walker that handled only the shapes its provider was expected to send. The
result was that every one of them priced most modern blocks at ~0: measured
on a 6,800-char block, ``OpenAITokenCounter`` returned 8 tokens for
``tool_result``/``thinking``/``document``/``mcp_tool_result`` and — its own
Responses shapes — ``output_text``/``refusal``; ``AnthropicTokenCounter``
returned 7 for ``thinking``/``document``, which are Anthropic's own.
Rather than add a fifth partial walker, this lets them borrow the audited one.
It is image-safe (base64 blobs get a pixel-based estimate instead of being
serialized and priced as text) and bounds oversized blobs, which a naive
``count_text(str(block))`` catch-all does not.View on GitHub (pinned to 322425c43b)
Solutions
- Install the backend dependency (tiktoken / transformers) and request a known model so the registry returns a real tokenizer.
- Branch on capability: guard decode calls with isinstance checks against a decoding-capable class or a try/except NotImplementedError.
- If decode is essential, pin a specific tokenizer explicitly (e.g. TiktokenTokenCounter) instead of relying on auto-detection.
Example fix
# before
text = tokenizer.decode([9450, 1917]) # NotImplementedError on estimator
# after
try:
text = tokenizer.decode([9450, 1917])
except NotImplementedError:
text = None # estimation-only backend; skip round-trip logic Defensive patterns
Strategy: try-catch
Validate before calling
decodable = hasattr(tokenizer, "decode") and type(tokenizer).decode is not BaseTokenizer.decode
Type guard
def supports_decoding(t) -> bool:
try:
t.decode([0])
return True
except NotImplementedError:
return False Try / catch
try:
text = tokenizer.decode(ids)
except NotImplementedError:
text = None Prevention
- Pin an encoding-capable tokenizer class when round-trips matter.
- Catch NotImplementedError at the boundary and degrade gracefully.
- Test decode paths against the exact backend used in production.
When it happens
Trigger: Calling decode() on an EstimatingTokenCounter or any fallback tokenizer obtained from the registry when the real backend was unavailable (missing dependency, unknown model, failed load).
Common situations: Environments without tiktoken/transformers installed; fallback kicked in after a tokenizer load failure (see HuggingFace fallback errors) and code still tries to decode; tests written against tiktoken running on minimal CI images.
Related errors
- {self.__class__.__name__} does not support encoding
- Encoding not available for {self.model} - tokenizer {self.to
- Decoding not available for {self.model} - tokenizer {self.to
- mistral-common is required for MistralTokenizer. Install wit
- No tokenizer available for {model}: {e}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/529ab869136885a1.
Report an issue: GitHub.