langchain-ai/langchain · error · TypeError

unsupported operand type(s) for +: '{type(self)}' and '{type

Error message

unsupported operand type(s) for +: '{type(self)}' and '{type(other)}'

What it means

Raised by RunLogPatch.__add__ when the right operand is not exactly a RunLogPatch. RunLogPatch objects accumulate JSON-patch ops and only support addition with their own kind; anything else (str, list, dict, RunLog) is a type error mirroring Python's built-in + semantics. The message reproduces the standard 'unsupported operand type(s)' wording with the concrete types.

Source

Thrown at libs/core/langchain_core/tracers/log_stream.py:154

    def __add__(self, other: RunLogPatch | Any) -> RunLog:
        """Combine two `RunLogPatch` instances.

        Args:
            other: The other `RunLogPatch` to combine with.

        Raises:
            TypeError: If the other object is not a `RunLogPatch`.

        Returns:
            A new `RunLog` representing the combination of the two.
        """
        if type(other) is RunLogPatch:
            ops = self.ops + other.ops
            state = jsonpatch.apply_patch(None, copy.deepcopy(ops))
            return RunLog(*ops, state=state)

        msg = f"unsupported operand type(s) for +: '{type(self)}' and '{type(other)}'"
        raise TypeError(msg)

    @override
    def __repr__(self) -> str:
        # 1:-1 to get rid of the [] around the list
        return f"RunLogPatch({pformat(self.ops)[1:-1]})"

    @override
    def __eq__(self, other: object) -> bool:
        return isinstance(other, RunLogPatch) and self.ops == other.ops

    __hash__ = None  # type: ignore[assignment]


class RunLog(RunLogPatch):
    """Run log."""

    state: RunState
    """Current state of the log, obtained from applying all ops in sequence."""

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Only combine RunLogPatch with RunLogPatch: total = patches[0]; for p in patches[1:]: total = total + p
  2. Use functools.reduce(operator.add, patches, patches[0]) with no foreign initial value
  3. To add a RunLog and a patch, put the RunLog on the left: run_log + run_log_patch (RunLog.__add__ handles that direction)
  4. Inspect types before adding when consuming astream_log programmatically

Example fix

# before
from functools import reduce
import operator
state = reduce(operator.add, patches, [])  # [] is not a RunLogPatch
# after
state = reduce(operator.add, patches)  # patches are all RunLogPatch; first is the seed
Defensive patterns

Strategy: type-guard

Validate before calling

from langchain_core.tracers.log_stream import RunLogPatch
assert all(type(p) is RunLogPatch for p in patches), [type(p) for p in patches]

Type guard

from langchain_core.tracers.log_stream import RunLogPatch
from typing import Any

def is_run_log_patch(x: Any) -> bool:
    return type(x) is RunLogPatch

Prevention

When it happens

Trigger: runnables stream logs via astream_log and caller code does patch + some_dict, patch + list_of_ops, or patch + run_log expecting concatenation; storing patches and accidentally adding a serialized ops list back; mixing RunLog and RunLogPatch in a reduction with functools.reduce over a heterogeneous list.

Common situations: Reducing streamed RunLogPatch chunks with a wrong initial value (e.g. [] instead of the first patch); assuming RunLogPatch behaves like a plain list of ops; tutorial code that adds the final RunLog back onto patches.

Related errors


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