langchain-ai/langchain · error · ValueError

Cannot concatenate ToolMessageChunks with different names.

Error message

Cannot concatenate ToolMessageChunks with different names.

What it means

Raised when two `ToolMessageChunk` objects are added together (`+`) but have different `tool_call_id` values. Chunk concatenation is how langchain-core aggregates streamed tool-message fragments into one message, and it is only valid between fragments of the same tool call. Note the message text says 'names' but the check is actually on `tool_call_id`.

Source

Thrown at libs/core/langchain_core/messages/tool.py:187

            )
        else:
            super().__init__(content=content, **kwargs)


class ToolMessageChunk(ToolMessage, BaseMessageChunk):
    """Tool 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["ToolMessageChunk"] = "ToolMessageChunk"  # type: ignore[assignment]

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

            return self.__class__(
                tool_call_id=self.tool_call_id,
                content=merge_content(self.content, other.content),
                artifact=merge_obj(self.artifact, other.artifact),
                additional_kwargs=merge_dicts(
                    self.additional_kwargs, other.additional_kwargs
                ),
                response_metadata=merge_dicts(
                    self.response_metadata, other.response_metadata
                ),
                id=self.id,
                status=_merge_status(self.status, other.status),
            )

        return super().__add__(other)

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Group streamed chunks by `tool_call_id` before concatenating (dict keyed by tool_call_id) instead of summing everything into one accumulator
  2. Verify you are not merging chunks from two different tool calls returned in the same streaming response
  3. If writing a custom aggregator, check `chunk.tool_call_id == other.tool_call_id` before `+` and raise/store separately otherwise
  4. If you build `ToolMessageChunk` manually, pass the exact `tool_call_id` from the originating AI message's `tool_calls` entry

Example fix

# before (mixes parallel tool calls)
total = None
for chunk in stream:
    total = chunk if total is None else total + chunk

# after
totals: dict[str, ToolMessageChunk] = {}
for chunk in stream:
    prev = totals.get(chunk.tool_call_id)
    totals[chunk.tool_call_id] = chunk if prev is None else prev + chunk
Defensive patterns

Strategy: validation

Validate before calling

def can_concat(a: ToolMessageChunk, b: ToolMessageChunk) -> bool:
    return a.tool_call_id == b.tool_call_id

# before accumulating streamed chunks:
if total is not None and not can_concat(total, chunk):
    raise ValueError(f'chunk belongs to tool_call_id={chunk.tool_call_id}, buffer holds {total.tool_call_id}')
total = total + chunk if total is not None else chunk

Type guard

from langchain_core.messages import ToolMessageChunk

def same_tool_call(a: ToolMessageChunk, b: ToolMessageChunk) -> bool:
    return isinstance(a, ToolMessageChunk) and isinstance(b, ToolMessageChunk) and a.tool_call_id == b.tool_call_id

Try / catch

try:
    merged = a + b
except ValueError as e:
    if 'different names' in str(e):
        # keep chunks separate per tool_call_id instead of crashing
        buffers[a.tool_call_id] = a
        buffers[b.tool_call_id] = b
    else:
        raise

Prevention

When it happens

Trigger: Calling `chunk1 + chunk2` (or `sum(chunks)`, or letting a streaming aggregator merge chunks) where the two `ToolMessageChunk` instances were created with different `tool_call_id` values, e.g. mixing fragments of two parallel tool calls into one accumulation buffer.

Common situations: Streaming agents that issue multiple tool calls per turn and accumulate all incoming chunks into a single variable without grouping by `tool_call_id`; manually re-indexing chunks after an id remapping step; writing a custom streaming callback that concatenates chunks out of order.

Related errors


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