Skip to content

sessions.json rotation (rename) + unlocked store read can cause random new sessionId ("memory wipe") without /new #18572

@sherly-techtree

Description

@sherly-techtree

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: rotateBytes was raised to 100mb as a workaround — original value was 10mb, 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() in src/auto-reply/reply/session.ts calls loadSessionStore(storePath) directly.
  • loadSessionStore() in src/config/sessions/store.ts swallows read/parse errors (including ENOENT when 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 file entries 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

  • /new hook 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)

  1. Acquire the session-store lock for the initial store read in initSessionState() (or retry under lock if load returns empty).
  2. 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.
  3. If sessions.json is missing/unreadable, fall back to latest sessions.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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions