openclaw - ✅(Solved) Fix sessions cleanup doesn't garbage-collect transcript files when index entries are pruned [3 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#76220Fetched 2026-05-03 04:40:32
View on GitHub
Comments
1
Participants
2
Timeline
13
Reactions
2
Author
Timeline (top)
referenced ×4cross-referenced ×3mentioned ×2subscribed ×2

When session index entries are pruned from sessions.json (via age-based pruneAfter, entry count maxEntries cap, or the rolling cron session window), the associated on-disk transcript files (.jsonl, .trajectory-path.json) are not deleted. Over time this causes unbounded directory growth that degrades filesystem performance and can wedge the gateway.

Root Cause

When session index entries are pruned from sessions.json (via age-based pruneAfter, entry count maxEntries cap, or the rolling cron session window), the associated on-disk transcript files (.jsonl, .trajectory-path.json) are not deleted. Over time this causes unbounded directory growth that degrades filesystem performance and can wedge the gateway.

Fix Action

Fix / Workaround

Partial workaround

PR fix notes

PR #76224: fix(sessions): sweep orphaned session artifacts during cleanup

Description (problem / solution / changelog)

Fixes #76220.

What

sessions cleanup walks the index and removes entries, but never removed the corresponding on-disk artifact files when entries were pruned by age (pruneAfter) or count (maxEntries). Files orphaned by earlier runs, crashes, or prior bugs accumulated indefinitely, causing large sessions directories that wedge the gateway on APFS and other filesystems sensitive to directory size.

How

src/config/sessions/disk-budget.ts

  • Add sweepOrphanedSessionArtifacts(params):
    • Read all files in the sessions directory via the existing readSessionsDirFiles helper.
    • Compute the referenced path set via the existing resolveReferencedSessionArtifactPaths helper (covers primary .jsonl, trajectory sidecars, and compaction checkpoints).
    • Delete files whose names match isPrimarySessionTranscriptFileName, isTrajectorySessionArtifactName, or isCompactionCheckpointTranscriptFileName but are not in the referenced set. Archive backups (.jsonl.deleted.*, .jsonl.bak-*) are intentionally skipped — they are managed by the archive retention path.
    • Supports dryRun: true for preview without deleting.
  • Export OrphanSweepResult { removedFiles, freedBytes }.

src/config/sessions/cleanup-service.ts

  • Import sweepOrphanedSessionArtifacts.
  • Add orphanedArtifacts field to SessionCleanupSummary.
  • previewStoreCleanup: run sweep in dry-run mode and fold its count into wouldMutate.
  • runSessionsCleanup (apply path): run sweep against the post-maintenance store (so entries pruned in this same run are already excluded from the referenced set).

src/commands/sessions-cleanup.ts

  • Text output: print removed file count when non-zero.
  • JSON output: orphanedArtifacts appears automatically in the summary.

Tests

Three new tests in src/config/sessions/disk-budget.test.ts:

  1. Deletes unreferenced primary transcript; preserves referenced one.
  2. Dry-run: reports count without deleting.
  3. Archive backups untouched even when not in index.

All 8 tests pass (5 original + 3 new). oxlint clean.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/commands/sessions-cleanup.ts (modified, +6/-0)
  • src/config/sessions/cleanup-service.ts (modified, +22/-3)
  • src/config/sessions/disk-budget.test.ts (modified, +62/-1)
  • src/config/sessions/disk-budget.ts (modified, +60/-0)

PR #76244: fix(sessions): sweep orphaned session artifacts during cleanup

Description (problem / solution / changelog)

Summary

  • Problem: sessions cleanup only removes store entries for stale/pruned sessions but leaves orphaned .jsonl transcript and trajectory files on disk — files whose session no longer exists in the store accumulate indefinitely.
  • Why it matters: Orphaned files persist forever and inflate the sessions directory without bound, bypassing the disk-budget guard entirely.
  • What changed: Added sweepOrphanedSessionArtifacts in disk-budget.ts that walks the sessions directory, builds the set of file paths referenced by the live store, and deletes any .jsonl / trajectory files not in that set. The sweep runs inside runExclusiveSessionStoreWrite with a fresh loadSessionStore snapshot to prevent a race where a concurrent session write creates a file between the snapshot and the directory scan.
  • What did NOT change (scope boundary): No changes to store entry pruning, budget eviction, or any other cleanup path.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

sessions cleanup applied budget/prune/cap logic to the in-memory store but never scanned the on-disk sessions directory for files whose store entry had already been removed. Once a session was pruned from the store, its transcript and trajectory files became permanently orphaned.

Test plan (for the reviewer)

  • disk-budget.test.tssweepOrphanedSessionArtifacts unit tests (dry-run, live, multi-format)
  • store.pruning.integration.test.ts — end-to-end pruning + sweep
  • sessions-cleanup.test.tsorphanedArtifacts field present in cleanup summary
  • server.sessions.store-rpc.test.ts — no regression in RPC cleanup path

AI-assisted.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/commands/sessions-cleanup.ts (modified, +6/-0)
  • src/config/sessions/cleanup-service.ts (modified, +29/-3)
  • src/config/sessions/disk-budget.test.ts (modified, +62/-1)
  • src/config/sessions/disk-budget.ts (modified, +60/-0)

PR #76250: fix(sessions): sweep orphaned session artifacts during cleanup (#76220)

Description (problem / solution / changelog)

Summary

  • Problem: sessions cleanup only removes store entries for stale/pruned sessions but leaves orphaned transcript (.jsonl) and trajectory (.json) files on disk. These accumulate silently and are never collected.
  • Root cause: cleanupSessions calls pruneSessionFiles which deletes the store entry, then calls cleanupStore which removes agents/ subdirs — but never touches transcript/trajectory files that match no remaining store entry.
  • Fix: After pruning runs, sweep the transcript and trajectory directories for files whose session key no longer exists in the (freshly reloaded) store, and delete them.

Changes

  • src/sessions/service.ts — add sweepOrphanedSessionArtifacts call after cleanupStore; wrapped in runExclusiveSessionStoreWrite with a fresh store load to prevent race with concurrent session writes
  • src/sessions/cleanup.tssweepOrphanedSessionArtifacts: enumerate .jsonl/.json files in transcript/trajectory dirs, extract session key from filename, delete if key absent from store
  • src/sessions/cleanup.test.ts — 3 regression tests: orphan files deleted, live session files preserved, missing dirs skipped

Fixes #76220

Co-authored-by: hclsys [email protected]

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/commands/sessions-cleanup.ts (modified, +6/-0)
  • src/config/sessions/cleanup-service.ts (modified, +29/-3)
  • src/config/sessions/disk-budget.test.ts (modified, +62/-1)
  • src/config/sessions/disk-budget.ts (modified, +60/-0)

Code Example

~/.openclaw/agents/orchestra/sessions/
├── sessions.json          (127 active entries)
├── 140 *.jsonl            (active transcripts)
├── 3,266 *.trajectory-path.json  (100% orphaned — 0 referenced by index)
├── 500 *.jsonl.deleted.*  (soft-delete tombstones)
├── 26 *.jsonl.bak-*       (compaction backups)
└── Total: 9,050 files, 495MB
RAW_BUFFERClick to expand / collapse

GitHub Issue Draft: sessions cleanup doesn't garbage-collect transcript files when index entries are pruned

Title: sessions cleanup doesn't garbage-collect orphaned transcript files when index entries are pruned

Labels: bug, storage


Summary

When session index entries are pruned from sessions.json (via age-based pruneAfter, entry count maxEntries cap, or the rolling cron session window), the associated on-disk transcript files (.jsonl, .trajectory-path.json) are not deleted. Over time this causes unbounded directory growth that degrades filesystem performance and can wedge the gateway.

Reproduction

  1. Configure an agent with multiple cron jobs using sessionTarget: "isolated" (each run creates a new session)
  2. Set session.maintenance.mode: "enforce" with pruneAfter: "7d" and maxEntries: 500
  3. Wait 2+ weeks

Expected: Transcript files for pruned sessions are removed when their index entries are pruned.

Actual: Index entries are removed, but .jsonl and .trajectory-path.json files remain on disk indefinitely. The sessions directory grows by hundreds of files per day.

Impact

On APFS (macOS), a sessions directory with ~9,000 files causes readdir() and file lock acquisition to take long enough to starve the Node event loop. Symptoms:

  • Gateway process alive (port bound) but unresponsive to Telegram/websocket messages
  • Health probes time out
  • kill -9 sometimes fails (process in uninterruptible kernel I/O wait)
  • openclaw sessions cleanup --enforce reports "remove 0" — it only walks the index, not the directory

Observed scale

~/.openclaw/agents/orchestra/sessions/
├── sessions.json          (127 active entries)
├── 140 *.jsonl            (active transcripts)
├── 3,266 *.trajectory-path.json  (100% orphaned — 0 referenced by index)
├── 500 *.jsonl.deleted.*  (soft-delete tombstones)
├── 26 *.jsonl.bak-*       (compaction backups)
└── Total: 9,050 files, 495MB

3 cron jobs × 5-minute intervals × isolated sessions = ~864 new sessions/day. With pruneAfter: 7d, the index stays bounded but the directory grows by ~640 orphan files/day.

Partial workaround

Setting session.maintenance.maxDiskBytes activates enforceSessionDiskBudget() which does walk the directory and removes orphaned .jsonl, .deleted.*, .reset.*, .bak.* files via isSessionArchiveArtifactName / isPrimarySessionTranscriptFileName.

However, .trajectory-path.json files match neither predicate (see artifacts.ts), so they accumulate regardless of budget settings. They're small individually (~257 bytes) but contribute directory entries that degrade APFS lookup performance.

Suggested fix

  1. When pruneStaleEntries() and capEntryCount() remove an index entry, also delete the associated transcript file (the sessionId → file path resolution already exists via resolveSessionTranscriptPathForEntry)
  2. Add .trajectory-path.json to isSessionArchiveArtifactName so the disk budget can clean them up
  3. Consider adding a --prune-orphans flag to openclaw sessions cleanup that walks the directory, diffs against the index, and removes unreferenced files (with an mtime safety filter to avoid racing with in-flight session creation)

Environment

  • OpenClaw 2026.4.2
  • macOS (APFS, Apple Silicon)
  • 26 configured agents, 3 cron jobs on the affected agent

extent analysis

TL;DR

Delete orphaned transcript files by modifying the pruneStaleEntries() and capEntryCount() functions to remove associated transcript files and updating the isSessionArchiveArtifactName predicate to include .trajectory-path.json files.

Guidance

  • Modify the pruneStaleEntries() and capEntryCount() functions to delete the associated transcript file when an index entry is removed.
  • Update the isSessionArchiveArtifactName predicate in artifacts.ts to include .trajectory-path.json files, allowing the disk budget to clean them up.
  • Consider adding a --prune-orphans flag to openclaw sessions cleanup to walk the directory, diff against the index, and remove unreferenced files.

Example

No code snippet is provided as the issue does not contain explicit code, but the suggested fix involves modifying the pruneStaleEntries() and capEntryCount() functions and updating the isSessionArchiveArtifactName predicate.

Notes

The provided solution assumes that the sessionId → file path resolution via resolveSessionTranscriptPathForEntry is accurate and reliable. Additionally, the --prune-orphans flag is suggested as a potential solution, but its implementation details are not provided.

Recommendation

Apply the suggested fix by modifying the pruneStaleEntries() and capEntryCount() functions and updating the isSessionArchiveArtifactName predicate, as this directly addresses the issue of orphaned transcript files not being deleted.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix sessions cleanup doesn't garbage-collect transcript files when index entries are pruned [3 pull requests, 1 comments, 2 participants]