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_kwargsView on GitHub (pinned to e32fa9a52e)
Solutions
- Reset your accumulator when a new message (or role) starts instead of continuing to `+`
- Guard before merging: only add when `left.role == right.role`
- 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
- Reset chunk accumulators when the role changes between streamed chunks
- Group chunks by (role, message id) before merging
- Unit test streaming merges against multi-role streams
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
- Cannot concatenate FunctionMessageChunks with different name
- unsupported operand type(s) for +: "{self.__class__.__name__
- SyncTextProjection requires a string delta
- SyncTextProjection requires a string final value
- SyncTextProjection received a non-string delta
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/a73938c663d167ec.
Report an issue: GitHub.