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
- Normalize values to `int` before accumulating: `int(x)` for numeric strings/floats, drop or zero `None`.
- Keep non-count metadata (model names, float costs) in a separate dict, not in the structure passed to usage accumulation.
- 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
- Coerce provider counts to int at the integration boundary.
- Keep metadata (names, float costs) out of usage-count dicts.
- Reject None usage fields early (treat absent as 0).
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
- {max_depth=} exceeded, unable to combine dicts.
- AsyncTextProjection received a non-string final value
- Invalid input type {type(model_input)}. Must be a PromptValu
- Unexpected generation type
- Expected generate to return a ChatResult, but got {type(chat
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/df7ad248dbce2851.
Report an issue: GitHub.