langchain-ai/langchain · error · TypeError

left and right are of different types. Left type: {type(lef

Error message

left and right are of different types. Left type:  {type(left)}. Right type: {type(right)}.

What it means

Raised by merge_dicts when left[key] and right[key] exist with different Python types — the per-key dispatch needs both sides to share a type to concatenate strings, merge dicts, or merge lists. This is the generic deep-merge utility behind prompt/data merging, not the message-chunk one. A type change on any shared key aborts the whole merge.

Source

Thrown at libs/core/langchain_core/utils/_merge.py:205

    Args:
        left: The first object to merge.
        right: The other object to merge.

    Returns:
        The merged object.

    Raises:
        TypeError: If the key exists in both dictionaries but has a different type.
        ValueError: If the two objects cannot be merged.
    """
    if left is None or right is None:
        return left if left is not None else right
    if type(left) is not type(right):
        msg = (
            f"left and right are of different types. Left type:  {type(left)}. Right "
            f"type: {type(right)}."
        )
        raise TypeError(msg)
    if isinstance(left, str):
        return left + right
    if isinstance(left, dict):
        return merge_dicts(left, right)
    if isinstance(left, list):
        return merge_lists(left, right)
    if left == right:
        return left
    msg = (
        f"Unable to merge {left=} and {right=}. Both must be of type str, dict, or "
        f"list, or else be two equal objects."
    )
    raise ValueError(msg)

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Normalize both sides to the same type for shared keys before calling merge_dicts (e.g. wrap scalars in a list)
  2. Restructure so the conflicting key is not present on both sides — pop it from one
  3. Validate inputs upstream with a schema (pydantic) so type drift is caught with a clearer error
  4. Catch TypeError and apply an explicit per-key resolution policy for known-volatile keys

Example fix

# before
from langchain_core.utils import merge_dicts
merged = merge_dicts({"docs": "a b"}, {"docs": ["a", "b"]})  # TypeError
# after
left = {"docs": ["a b"]}
merged = merge_dicts(left, {"docs": ["a", "b"]})  # list + list merges
Defensive patterns

Strategy: type-guard

Validate before calling

shared = set(left) & set(right)
for k in shared:
    if type(left[k]) is not type(right[k]):
        msg = f"key {k!r}: {type(left[k]).__name__} vs {type(right[k]).__name__}"
        raise TypeError(msg)  # clearer than the library's message

Type guard

from typing import Any

def dict_types_compatible(left: dict[str, Any], right: dict[str, Any]) -> bool:
    return all(
        type(left[k]) is type(right[k])
        for k in set(left) & set(right)
    )

Prevention

When it happens

Trigger: merge_dicts({'a': 'x'}, {'a': ['x']}); merging template partials where one side supplies a string and the other a list for the same variable; merging config/data dicts assembled from JSON sources with schema drift; example_prompt kwargs built from mixed sources.

Common situations: Prompt templates with partial variables whose type differs between code defaults and runtime inputs; merging serialized examples where a field changed type between versions; dataclass/to-dict conversions producing lists vs scalars for the same field.

Related errors


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