#15882: fix: move session entry computation inside store lock to prevent race conditions
commands
stale
size: S
Cluster:
Session Lock Improvements
## Summary
Fixes a race condition in `updateSessionStoreAfterAgentRun()` where the updated session entry was computed **outside** the write lock using a potentially-stale in-memory snapshot.
## Problem
In multi-agent setups (multiple agents sharing one session store file), two concurrent agent runs could:
1. Both read the same in-memory `sessionStore` snapshot
2. Compute their updates independently
3. The last writer silently overwrites the other's changes
This caused **session data contamination** across agents — users bound to different agents via Telegram DM bindings would receive each other's messages.
## Fix
Moved the entry construction into the `updateSessionStore()` mutator callback, which:
- Re-reads from disk **inside** the lock (via `loadSessionStore({ skipCache: true })`)
- Guarantees each write merges against the latest persisted state
- Keeps the caller's in-memory reference consistent
## Testing
Reproduced in a 3-agent setup (main + 2 DM-bound agents via Telegram bindings). Before the fix, concurrent messages caused cross-agent session overwrites. After the fix, each agent's session state remains isolated.
## Related
- Refs #12550 (Session Management and Data Integrity Defects)
- Partially addresses concerns in #14411 (reducing blast radius of shared state)
---
*First contribution from the CPIC (Colegio de Profesionales en Informática y Computación, Costa Rica) team. We run OpenClaw in production with multi-agent Telegram bindings and hit this issue directly.*
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates `updateSessionStoreAfterAgentRun()` to construct the next `SessionEntry` *inside* the `updateSessionStore()` mutator callback. Because `updateSessionStore()` re-reads the session store from disk with `skipCache: true` while holding the per-store write lock, building/merging the entry inside the callback prevents concurrent agents (sharing the same store file) from computing updates against a stale in-memory snapshot and then overwriting each other.
Net effect: session store writes now merge against the latest persisted state under lock, and the caller’s in-memory `sessionStore[sessionKey]` is updated within the same critical section to keep the in-process snapshot consistent with what’s written to disk.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- Change is narrowly scoped to moving session-entry computation into the already-existing locked updateSessionStore mutator, aligning with updateSessionStore’s contract (fresh read inside lock, then mutate, then save). No behavioral changes beyond eliminating a lost-update race; no new I/O paths or error handling changes introduced.
- No files require special attention
<sub>Last reviewed commit: 3e72d9c</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#4664: fix: per-session metadata files to eliminate lock contention
by tsukhani · 2026-01-30
84.3%
#21828: fix: acquire session write lock in delivery mirror and gateway chat...
by inkolin · 2026-02-20
83.9%
#19328: Fix: preserve modelOverride in agent handler (#5369)
by CodeReclaimers · 2026-02-17
82.3%
#10725: fix: re-read session store inside lock in updateSessionStoreEntry
by Yida-Dev · 2026-02-06
82.3%
#15628: fix: resolve session write lock race condition
by 1kuna · 2026-02-13
80.3%
#20188: fix: Update sessionFile path when rolling to new session in cron jobs
by jriff · 2026-02-18
80.2%
#20336: fix(sessions): resolve transcriptPath using agentId when storePath ...
by Limitless2023 · 2026-02-18
80.1%
#16609: fix: resolve session store race condition and contextTokens updates
by battman21 · 2026-02-14
79.8%
#20431: fix(sessions): add session contamination guards and self-leak lock ...
by marcomarandiz · 2026-02-18
79.0%
#15176: fix(sessions): allow channel-routed session IDs and cross-agent paths
by cathrynlavery · 2026-02-13
78.8%