{"record":{"id":"b4e5751aa10bfaf1","repo":"langchain-ai/langchain","slug":"cannot-concatenate-functionmessagechunks-with-diff","errorCode":null,"errorMessage":"Cannot concatenate FunctionMessageChunks with different names.","messagePattern":"Cannot concatenate FunctionMessageChunks with different names\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/messages/function.py","lineNumber":48,"sourceCode":"    type: Literal[\"function\"] = \"function\"\n    \"\"\"The type of the message (used for serialization).\"\"\"\n\n\nclass FunctionMessageChunk(FunctionMessage, BaseMessageChunk):\n    \"\"\"Function Message chunk.\"\"\"\n\n    # Ignoring mypy re-assignment here since we're overriding the value\n    # to make sure that the chunk variant can be discriminated from the\n    # non-chunk variant.\n    type: Literal[\"FunctionMessageChunk\"] = \"FunctionMessageChunk\"  # type: ignore[assignment]\n    \"\"\"The type of the message (used for serialization).\"\"\"\n\n    @override\n    def __add__(self, other: Any) -> BaseMessageChunk:  # type: ignore[override]\n        if isinstance(other, FunctionMessageChunk):\n            if self.name != other.name:\n                msg = \"Cannot concatenate FunctionMessageChunks with different names.\"\n                raise ValueError(msg)\n\n            return self.__class__(\n                name=self.name,\n                content=merge_content(self.content, other.content),\n                additional_kwargs=merge_dicts(\n                    self.additional_kwargs, other.additional_kwargs\n                ),\n                response_metadata=merge_dicts(\n                    self.response_metadata, other.response_metadata\n                ),\n                id=self.id,\n            )\n\n        return super().__add__(other)\n","sourceCodeStart":30,"sourceCodeEnd":63,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/messages/function.py#L30-L63","documentation":"Raised by FunctionMessageChunk.__add__ when two chunks whose `name` attributes differ are merged with `+`. Chunks of a legacy FunctionMessage belong to one function invocation identified by name; merging across names would corrupt that identity, so it is rejected.","triggerScenarios":"`chunk1 + chunk2` where `chunk1.name == \"search\"` and `chunk2.name == \"calculate\"`; accumulating streamed FunctionMessageChunks from multiple tool outputs into one buffer without resetting between tools.","commonSituations":"Legacy (pre-tool-calls API) streaming code that reduces all function chunks in a turn; parallel function calls whose outputs are interleaved in one stream; old agents migrated forward that still use FunctionMessage.","solutions":["Start a new accumulator per function name / per tool invocation","Guard merges: only `+` when `self.name == other.name`","Migrate from FunctionMessage to the modern `ToolMessage`/tool_calls API, which keys merges by tool_call_id"],"exampleFix":"# before\nacc = None\nfor chunk in function_chunks:\n    acc = chunk if acc is None else acc + chunk  # ValueError across names\n\n# after\nbuffers = {}\nfor chunk in function_chunks:\n    buffers[chunk.name] = buffers.get(chunk.name, None) + chunk if buffers.get(chunk.name) else chunk","handlingStrategy":"type-guard","validationCode":"def same_name(a, b) -> bool:\n    return getattr(a, \"name\", None) == getattr(b, \"name\", None)","typeGuard":"from langchain_core.messages import FunctionMessageChunk\n\ndef is_same_function_chunk(a: FunctionMessageChunk, b: FunctionMessageChunk) -> bool:\n    return a.name == b.name","tryCatchPattern":null,"preventionTips":["Buffer function chunks per name, not globally","Migrate legacy FunctionMessage code to ToolMessage with tool_call_ids","Reset accumulators at tool-output boundaries in stream handlers"],"tags":["messages","streaming","chunks","function-calling","legacy"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}