[PR #6891] checkpoint: enforce string thread IDs in sqlite/postgres savers #5380

Open
opened 2026-02-20 17:51:37 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langchain-ai/langgraph/pull/6891

State: open
Merged: No


Problem

Checkpoint key identity can alias when non-string thread_id values are coerced, which risks collisions (for example 1 vs "1") and weakens replay/audit guarantees.

Why now

Multi-tenant checkpoint usage depends on strict, deterministic key contracts, and implicit coercion undermines that contract.

What changed

  • Added get_thread_id(config) in checkpoint base to enforce thread_id is a string.
  • Switched sqlite and postgres saver paths to use enforced thread_id instead of implicit coercion.
  • Updated sync/async + shallow postgres paths and sync/async sqlite paths.
  • Added sqlite regression tests that assert non-string thread_id fails closed.

Validation

  • make format && make lint && make test TEST=tests/test_memory.py (libs/checkpoint)
  • make format && make lint (libs/checkpoint-postgres)
  • make test TEST="tests/test_sync.py -k test_search" (libs/checkpoint-postgres)
  • make test TEST="tests/test_async.py -k test_asearch" (libs/checkpoint-postgres)
  • make format && make lint (libs/checkpoint-sqlite)
  • make test TEST=tests/test_sqlite.py (libs/checkpoint-sqlite)
  • make test TEST=tests/test_aiosqlite.py (libs/checkpoint-sqlite)

Refs #6890

**Original Pull Request:** https://github.com/langchain-ai/langgraph/pull/6891 **State:** open **Merged:** No --- ## Problem Checkpoint key identity can alias when non-string `thread_id` values are coerced, which risks collisions (for example `1` vs `"1"`) and weakens replay/audit guarantees. ## Why now Multi-tenant checkpoint usage depends on strict, deterministic key contracts, and implicit coercion undermines that contract. ## What changed - Added `get_thread_id(config)` in checkpoint base to enforce `thread_id` is a string. - Switched sqlite and postgres saver paths to use enforced `thread_id` instead of implicit coercion. - Updated sync/async + shallow postgres paths and sync/async sqlite paths. - Added sqlite regression tests that assert non-string `thread_id` fails closed. ## Validation - `make format && make lint && make test TEST=tests/test_memory.py` (libs/checkpoint) ✅ - `make format && make lint` (libs/checkpoint-postgres) ✅ - `make test TEST="tests/test_sync.py -k test_search"` (libs/checkpoint-postgres) ✅ - `make test TEST="tests/test_async.py -k test_asearch"` (libs/checkpoint-postgres) ✅ - `make format && make lint` (libs/checkpoint-sqlite) ✅ - `make test TEST=tests/test_sqlite.py` (libs/checkpoint-sqlite) ✅ - `make test TEST=tests/test_aiosqlite.py` (libs/checkpoint-sqlite) ✅ Refs #6890
yindo added the pull-request label 2026-02-20 17:51:37 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#5380