langchain-ai/langchain · error · ValueError

Cannot concatenate ChatMessageChunks with different roles.

Error message

Cannot concatenate ChatMessageChunks with different roles.

What it means

Raised by ChatMessageChunk.__add__ when two chunks with different `role` values are concatenated with `+`. Chunk merging is only defined for pieces of the same logical message; a role change mid-stream would silently corrupt the message, so langchain-core refuses.

Source

Thrown at libs/core/langchain_core/messages/chat.py:39

    type: Literal["chat"] = "chat"
    """The type of the message (used during serialization)."""


class ChatMessageChunk(ChatMessage, BaseMessageChunk):
    """Chat Message chunk."""

    # Ignoring mypy re-assignment here since we're overriding the value
    # to make sure that the chunk variant can be discriminated from the
    # non-chunk variant.
    type: Literal["ChatMessageChunk"] = "ChatMessageChunk"  # type: ignore[assignment]
    """The type of the message (used during serialization)."""

    @override
    def __add__(self, other: Any) -> BaseMessageChunk:  # type: ignore[override]
        if isinstance(other, ChatMessageChunk):
            if self.role != other.role:
                msg = "Cannot concatenate ChatMessageChunks with different roles."
                raise ValueError(msg)

            return self.__class__(
                role=self.role,
                content=merge_content(self.content, other.content),
                additional_kwargs=merge_dicts(
                    self.additional_kwargs, other.additional_kwargs
                ),
                response_metadata=merge_dicts(
                    self.response_metadata, other.response_metadata
                ),
                id=self.id,
            )
        if isinstance(other, BaseMessageChunk):
            return self.__class__(
                role=self.role,
                content=merge_content(self.content, other.content),
                additional_kwargs=merge_dicts(
                    self.additional_kwargs, other.additional_kwargs

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Reset your accumulator when a new message (or role) starts instead of continuing to `+`
  2. Guard before merging: only add when `left.role == right.role`
  3. If roles genuinely differ, keep them as separate messages rather than merging

Example fix

# before
acc = None
for chunk in stream:
    acc = chunk if acc is None else acc + chunk  # ValueError across roles

# after
acc = None
for chunk in stream:
    if acc is None or acc.role == chunk.role:
        acc = chunk if acc is None else acc + chunk
    else:
        finalize(acc); acc = chunk
Defensive patterns

Strategy: type-guard

Validate before calling

def same_role(a, b) -> bool:
    return getattr(a, "role", None) == getattr(b, "role", None)

Type guard

from langchain_core.messages import ChatMessageChunk

def is_same_role_chunk(a: ChatMessageChunk, b: ChatMessageChunk) -> bool:
    return a.role == b.role

Prevention

When it happens

Trigger: `chunk_a + chunk_b` where `chunk_a.role == "assistant"` and `chunk_b.role == "user"` (or any differing roles); commonly happens when concatenating chunks from different messages in a stream, or merging an accumulated chunk with a stray chunk from a new message.

Common situations: Custom streaming code that reduces all incoming chunks with `+` without resetting the accumulator when the role/message changes; mixing chunks from parallel streams; unit tests that merge arbitrary chunks.

Related errors


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