langchain-ai/langchain · error · ValueError

Unknown value types: {types}. Only dict and int values are s

Error message

Unknown value types: {types}. Only dict and int values are supported.

What it means

Raised by `_dict_int_op` in `langchain_core.utils.usage` when, while combining two usage-style dicts, a key's value in at least one dict is neither an `int` nor a `dict` (note `bool` counts as int; floats, strings, None, lists fail). The helper exists to sum integer counters (token counts), so any other type is rejected with `ValueError` listing the offending types.

Source

Thrown at libs/core/langchain_core/utils/usage.py:60

        if isinstance(left.get(k, default), int) and isinstance(
            right.get(k, default), int
        ):
            combined[k] = op(left.get(k, default), right.get(k, default))
        elif isinstance(left.get(k, {}), dict) and isinstance(right.get(k, {}), dict):
            combined[k] = _dict_int_op(
                left.get(k, {}),
                right.get(k, {}),
                op,
                default=default,
                depth=depth + 1,
                max_depth=max_depth,
            )
        else:
            types = [type(d[k]) for d in (left, right) if k in d]
            msg = (
                f"Unknown value types: {types}. Only dict and int values are supported."
            )
            raise ValueError(msg)  # noqa: TRY004
    return combined

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Normalize values to `int` before accumulating: `int(x)` for numeric strings/floats, drop or zero `None`.
  2. Keep non-count metadata (model names, float costs) in a separate dict, not in the structure passed to usage accumulation.
  3. Coerce provider responses in your integration's usage-extraction step so only `dict[str, int|dict]` reaches the combiner.

Example fix

# before
usage = {"input_tokens": "128", "model": "gpt-4o"}  # str + str metadata
_dict_int_op(usage, other, operator.add)  # ValueError: Unknown value types

# after
usage = {"input_tokens": int("128")}  # ints only; metadata kept elsewhere
_dict_int_op(usage, other, operator.add)
Defensive patterns

Strategy: validation

Validate before calling

def normalize_usage(d: dict) -> dict:
    out = {}
    for k, v in d.items():
        if v is None:
            continue
        if isinstance(v, dict):
            out[k] = normalize_usage(v)
        elif isinstance(v, (int, float, str)) and not isinstance(v, bool):
            out[k] = int(v)
        else:
            raise TypeError(f"unsupported usage value {k}={v!r}")
    return out

usage = normalize_usage(raw_provider_usage)  # now safe for _dict_int_op

Type guard

def is_int_dict(d: Any) -> TypeGuard[dict[str, int | dict]]:
    return isinstance(d, dict) and all(
        isinstance(v, (int, dict)) for v in d.values()
    )

Try / catch

try:
    total = _dict_int_op(left, right, operator.add)
except ValueError as e:
    logger.warning("skipping usage merge: %s", e)
    total = left

Prevention

When it happens

Trigger: Aggregating token usage where one side carries a non-int value: `input_tokens: 12.0` (float), a provider-returned string count `"12"`, `None` from an optional field, or a list under a key that the other dict treats as int/dict. Also triggered by directly calling `_dict_int_op` with arbitrary payloads.

Common situations: Custom LLM providers returning numeric token counts as strings or floats; optional usage fields set to `None` when absent; merging usage dicts of different shapes across model versions; adding metadata (model name, cost as float) into the same dict that feeds usage accumulation.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/df7ad248dbce2851. Report an issue: GitHub.