Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LangGraph same-thread concurrent writer checkpoint fork repro

Independent XBSTACK reproduction of the write-ownership gap discussed in LangGraph issue #8796 and the corresponding LangChain Forum thread.

Question

Does a PostgreSQL-backed LangGraph Checkpointer make two legitimate workers safe concurrent writers for the same thread_id?

This experiment tests one narrow production boundary:

  1. Worker A starts a plain MessagesState graph and is frozen inside its second deterministic model call.
  2. Worker B resumes the same thread_id with invoke(None, config) and finishes.
  3. Worker A is thawed and continues writing from the checkpoint that was current before B took over.
  4. The script queries the real checkpoints table and checks whether the parent checkpoint has more than one child, whether B returned success, and whether B's committed checkpoints become unreachable from the final tip.

No external model/API is used. The model is scripted and deterministic. PostgreSQL is provided locally by pgserver; Docker is not required.

Pinned environment

  • Test date: 2026-09-08
  • Python: 3.12
  • langgraph: 1.2.11
  • langgraph-checkpoint: 4.2.0
  • langgraph-checkpoint-postgres: 3.1.2
  • langchain-core: 1.6.1
  • psycopg: 3.3.4
  • pgserver: 0.1.4

Run

uv venv --python 3.12 .venv
VIRTUAL_ENV=$PWD/.venv uv pip install -r requirements.txt
.venv/bin/python repro.py
.venv/bin/python fencing_control.py

repro.py writes results/verification.json. A successful reproduction ends with:

"result": "REPRODUCED"

The expected evidence is:

  • both worker processes exit successfully;
  • the checkpoint chain contains a fork whose parent is the checkpoint that was the tip when Worker A was frozen;
  • Worker B returns final answer from B to its caller;
  • after Worker A resumes, at least one checkpoint committed during B's run is no longer reachable from the final tip;
  • the final thread tip contains Worker A's terminal answer instead.

Fencing control

fencing_control.py demonstrates the minimum application-level ownership concept with a versioned owner row:

  • Worker A starts with ownership version 1;
  • Worker B atomically claims version 2;
  • Worker A's stale version 1 is rejected before it is allowed to write;
  • Worker B remains the current owner.

This control is intentionally limited. It is not an upstream LangGraph fix and it is not atomic with PostgresSaver writes. A production fence must be integrated at the write boundary or enforced by an orchestration layer that can guarantee a stale worker cannot pass the ownership check and then write later.

Scope / non-claims

This repository does not prove that every LangGraph version or every saver behaves identically. It tests the pinned versions above, on one machine, with two OS processes and one embedded PostgreSQL instance. It does not model a multi-machine network partition, PgBouncer transaction pooling, clock skew, or external tool side effects.

The experiment is designed to verify the narrow statement used in the XBSTACK production guides: database transaction consistency is not the same thing as same-thread write ownership.

Upstream evidence

Related XBSTACK guides

Attribution

The failure scenario follows the same high-level freeze/takeover/thaw idea documented by the upstream issue and bharatnpti/langgraph-write-ownership, which is MIT licensed. This XBSTACK fixture is a smaller, plain-MessagesState implementation written to independently verify the checkpoint-chain ownership claim without Deep Agents or a real provider.

About

Verified LangGraph 1.2.11 same-thread concurrent writer checkpoint-fork reproduction with PostgresSaver and fencing control

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages