-
-
Notifications
You must be signed in to change notification settings - Fork 69.5k
sessions.json rotation (rename) + unlocked store read can cause random new sessionId ("memory wipe") without /new #18572
Description
Summary
We observed ~15+ "random session resets" (agent loses context mid-conversation) across both Discord and Telegram in a single day. These were NOT compactions and were NOT invoked by /new or /reset.
The symptom is OpenClaw creating a brand-new sessionId for an existing sessionKey, so the agent truly has an empty transcript and responds with no memory.
Expected
A given sessionKey should keep the same sessionId unless a reset trigger occurs (/new//reset), daily reset, or idle reset.
Actual
For active chats (Discord channels + Telegram groups), OpenClaw starts fresh sessions mid-thread (new sessionId), with no reset command and no .jsonl.reset.* archive.
Environment
- OpenClaw version: 2026.2.15
- Node: v22.22.0
- OS: Darwin 25.2.0 (arm64, Apple Silicon Mac Mini)
- Store file size: ~14–17 MB (at time of rotations)
- Rotation count in a single day's log: 772 rotations
Relevant config
{
"session": {
"reset": {
"mode": "idle",
"idleMinutes": 525600
},
"maintenance": {
"mode": "enforce",
"pruneAfter": "7d",
"maxEntries": 500,
"rotateBytes": "100mb"
}
}
}Note:
rotateByteswas raised to100mbas a workaround — original value was10mb, which caused constant rotations at the ~15MB store size.
Root cause analysis (confirmed)
When sessions.json exceeds rotateBytes, OpenClaw rotates the session store by renaming:
sessions.json → sessions.json.bak.<timestamp>
This briefly leaves NO sessions.json on disk.
Session initialization reads the store WITHOUT acquiring the session-store lock:
initSessionState()insrc/auto-reply/reply/session.tscallsloadSessionStore(storePath)directly.loadSessionStore()insrc/config/sessions/store.tsswallows read/parse errors (includingENOENTwhen the file is missing) and returns{}.
If an inbound Discord/Telegram message is processed during the short "sessions.json missing" window created by rotation, the store loads as {}, the session entry for that sessionKey is missing, and OpenClaw generates a fresh sessionId.
This looks exactly like a random memory wipe with no slash command.
Evidence
Rotation frequency (today's log, Feb 16 2026)
- 772
rotated session store fileentries in a single day's log - Rotations occurring every few seconds (e.g. 16:55:55Z → 16:56:44Z → 16:57:07Z → 16:57:21Z → 16:57:37Z → 16:57:38Z)
- Store size at rotation: ~16.5 MB consistently
Sample log entries (timestamps in UTC)
2026-02-16T16:55:55Z rotated session store file sizeBytes=17560692 backupPath=sessions.json.bak.1771260955514
2026-02-16T16:56:44Z rotated session store file sizeBytes=16535854 backupPath=sessions.json.bak.1771261004211
2026-02-16T16:56:44Z rotated session store file sizeBytes=16535854 backupPath=sessions.json.bak.1771261004413
2026-02-16T16:57:07Z rotated session store file sizeBytes=16535854 backupPath=sessions.json.bak.1771261027158
2026-02-16T16:57:21Z rotated session store file sizeBytes=16535852 backupPath=sessions.json.bak.1771261041980
2026-02-16T16:57:37Z rotated session store file sizeBytes=16535852 backupPath=sessions.json.bak.1771261057277
2026-02-16T16:57:38Z rotated session store file sizeBytes=16535852 backupPath=sessions.json.bak.1771261058456 ← 1 second gap
2026-02-16T16:57:38Z rotated session store file sizeBytes=16535852 backupPath=sessions.json.bak.1771261058612 ← 156ms gap
No /new or /reset near rotation times
/newhook triggers in today's log cluster around 13:34–14:09 UTC- Rotation storm is at 16:55+ UTC — no overlap
- Idle reset effectively disabled (
idleMinutes: 525600= 1 year)
Suggested fixes (any of these)
- Acquire the session-store lock for the initial store read in
initSessionState()(or retry under lock if load returns empty). - Change store rotation to avoid a missing-file window — copy-then-rename instead of rename-then-recreate (atomic swap), or write new store first then rotate old.
- If
sessions.jsonis missing/unreadable, fall back to latestsessions.json.bak.*instead of treating it as an empty store.
Workaround
Raising session.maintenance.rotateBytes above the current store size (e.g. "100mb") and restarting the gateway stopped the constant rotations and stopped the random resets immediately.