Skip to content

Usage-cost cache leaves orphaned .usage-cost-cache.json.*.tmp files in agent session stores #78939

Description

@Tramsrepus

Repo: https://github.com/openclaw/openclaw
Observed OpenClaw version: 2026.5.6

Summary

I found a real disk-leak issue in OpenClaw's session usage-cost cache.

In production, agent session directories accumulated orphaned temp files named like:

  • .usage-cost-cache.json.<pid>.<timestamp>.tmp

These files were not being cleaned up and built up over time.

On one live system, I found:

  • 303 leaked temp files
  • about 1.877 GB consumed by those temp files alone

This was separate from other session artifacts such as reset/checkpoint/trajectory files.

Why this looks like a real current bug

The current bundled code in 2026.5.6 appears to write the usage-cost cache via:

async function writeUsageCostCache(cachePath, cache) {
  const tmpPath = `${cachePath}.${process.pid}.${Date.now()}.tmp`;
  await fs.promises.mkdir(path.dirname(cachePath), { recursive: true });
  await fs.promises.writeFile(tmpPath, `${JSON.stringify(cache)}\n`, "utf-8");
  await fs.promises.rename(tmpPath, cachePath);
}

Observed local file/line range:

  • dist/session-cost-usage-CoJqCXu7.js:191-195

The important problem is that this path does not appear to remove tmpPath in a finally block if the rename fails, the process is interrupted, or the write path aborts after the temp file is created.

In the same module, the lock writer does clean up its temp file in a finally block:

async function writeUsageCostCacheLockAtomically(lockPath, lock) {
  const tempPath = `${lockPath}.${process.pid}.${process.hrtime.bigint()}.tmp`;
  await fs.promises.writeFile(tempPath, `${JSON.stringify(lock)}\n`, { flag: "wx" });
  try {
    await fs.promises.link(tempPath, lockPath);
  } finally {
    await fs.promises.rm(tempPath, { force: true }).catch(() => void 0);
  }
}

Observed local file/line range:

  • dist/session-cost-usage-CoJqCXu7.js:103-109

So the temp-file-cleanup pattern already exists nearby, but the main usage-cost cache write path does not appear to use it.

Impact

This can silently bloat agent session directories over time, especially on busy systems.

In my case, these leaked temp files were found across multiple agent session stores and had to be deleted manually.

This is easy to miss because the real cache file still exists and works, while the orphaned temp files just pile up beside it.

What I observed

Relevant production evidence:

  • pattern: .usage-cost-cache.json.*.tmp
  • count found before cleanup: 303
  • total size before cleanup: about 1.877 GB
  • after manual cleanup, current count returned to 0

The leak was found inside agent session directories under paths like:

  • D:\Mr_OC\.openclaw\agents\viggo\sessions
  • D:\Mr_OC\.openclaw\agents\tom\sessions
  • D:\Mr_OC\.openclaw\agents\jeff\sessions
  • D:\Mr_OC\.openclaw\agents\doc\sessions

Expected behavior

Temporary usage-cost cache files should not remain on disk indefinitely after interrupted or failed writes.

Suggested fix directions

  1. Make writeUsageCostCache() clean up its temp file in a finally block when appropriate.
  2. Consider startup or maintenance cleanup of stale .usage-cost-cache.json.*.tmp files.
  3. Consider logging a warning when orphaned temp files are detected, because otherwise this leak is very easy to miss.

Notes

I am not reporting the normal session archive/checkpoint growth here.
This issue is specifically about the orphaned usage-cost-cache temp files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.no-staleExclude from stale automation

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions