openclaw - 💡(How to fix) Fix Unclosed FileHandle on session JSONL lock crashes gateway on Node ≥24 under sustained session-store load

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…

The gateway leaks unclosed fs.FileHandle references on session transcript .jsonl.lock files. On Node 22 (the supported LTS line per the 2026.5.18 release notes) this surfaces only as a deprecation warning, but on Node 24+ V8 promotes FileHandle GC to a fatal ERR_INVALID_STATE, which crashes the gateway process whenever the V8 GC happens to sweep one before OC closes it.

In our deployment this manifests as a chronic ~2-hour crash cadence on a single bot that accumulated a large session backlog (2,446 JSONL files in ~/.openclaw/agents/main/sessions/). Other bots on the same host / OC / Node version don't crash — they have 5–100 sessions on disk and don't generate enough open-handle pressure for V8 to ever GC a leaked one.

Error Message

Every ~2h a stability bundle is written with reason: uncaught_exception and this error:

A FileHandle object was closed during garbage collection. This used to be allowed with a deprecation warning but is now considered an error. Please close FileHandle objects explicitly. File descriptor: <N> (/Users/<bot>/.openclaw/agents/main/sessions/<uuid>.jsonl.lock) warn marked 1 interrupted main session(s) from stale transcript locks warn marked interrupted main session failed: agent:main:main:heartbeat (transcript tail is not resumable) OC's session-store code opens FileHandles for transcript locks during heartbeat-session write / scan operations and doesn't always go through an explicit `.close()` on every return path (likely error paths or interrupted writes). On Node 22 this is harmless because GC-close was warn-only; on Node 24+ it's fatal.

  • Error returns mid-write "error": { "name": "Error", "message": "A FileHandle object was closed during garbage collection. This used to be allowed with a deprecation warning but is now considered an error. Please close FileHandle objects explicitly. File descriptor: 38 (/Users/<bot>/.openclaw/agents/main/sessions/<redacted-uuid>.jsonl.lock)" I have 10 stability bundles over a 31h window with the same error signature (different FD / UUID each time) — happy to share more if useful.

Root Cause

After ~4 crashes in 8h, macOS launchd's anti-thrash kicks in (`Successfully spawned … because inefficient`) — downstream symptom, not the root cause.

Fix Action

Fix / Workaround

Workaround for affected users

RAW_BUFFERClick to expand / collapse

Summary

The gateway leaks unclosed fs.FileHandle references on session transcript .jsonl.lock files. On Node 22 (the supported LTS line per the 2026.5.18 release notes) this surfaces only as a deprecation warning, but on Node 24+ V8 promotes FileHandle GC to a fatal ERR_INVALID_STATE, which crashes the gateway process whenever the V8 GC happens to sweep one before OC closes it.

In our deployment this manifests as a chronic ~2-hour crash cadence on a single bot that accumulated a large session backlog (2,446 JSONL files in ~/.openclaw/agents/main/sessions/). Other bots on the same host / OC / Node version don't crash — they have 5–100 sessions on disk and don't generate enough open-handle pressure for V8 to ever GC a leaked one.

Environment

  • OC: 2026.5.18 (npm)
  • Node: 25.9.0 (three majors above the documented Node 22.19 minimum, but well within what users on rolling-release Homebrew get by default)
  • OS: macOS 26.4.1 arm64
  • Bot has been running ~30h under sustained activity; heartbeat interval is the gateway default 7,200,000ms (gateway/heartbeat: {"intervalMs":7200000} heartbeat: started)
  • Session count on disk: 2,446 .jsonl files; no stale .lock files at rest

Symptom

Every ~2h a stability bundle is written with reason: uncaught_exception and this error:

A FileHandle object was closed during garbage collection. This used to be allowed with a deprecation warning but is now considered an error. Please close FileHandle objects explicitly. File descriptor: <N> (/Users/<bot>/.openclaw/agents/main/sessions/<uuid>.jsonl.lock)

The FD number and session UUID rotate; the path pattern is invariant: always a .jsonl.lock file in the agent's `sessions/` directory.

On the next launchd-driven restart the gateway's `main-session-restart-recovery` logs:

``` warn marked 1 interrupted main session(s) from stale transcript locks warn marked interrupted main session failed: agent:main:main:heartbeat (transcript tail is not resumable) ```

confirming the leaked handle was held by the heartbeat session.

After ~4 crashes in 8h, macOS launchd's anti-thrash kicks in (`Successfully spawned … because inefficient`) — downstream symptom, not the root cause.

Reproducer

  1. Run gateway on Node ≥24
  2. Accumulate ~2,000+ session JSONL files in the agent's sessions directory
  3. Let the default 2h heartbeat fire several times
  4. Crash typically occurs within 2–4 hours

Likely root cause

OC's session-store code opens FileHandles for transcript locks during heartbeat-session write / scan operations and doesn't always go through an explicit `.close()` on every return path (likely error paths or interrupted writes). On Node 22 this is harmless because GC-close was warn-only; on Node 24+ it's fatal.

The stability bundle includes the diagnostic-phase log up to seq=181 (load → normalize → plugins → channels) but does not include the throwing stack frame, since the crash is in V8's GC sweep rather than user code.

Suggested fix direction

Audit `FileHandle` open call sites in the session-store layer (anywhere transcript locks are taken) for non-explicit close paths, especially:

  • Error returns mid-write
  • Heartbeat-session interrupt handling on shutdown
  • Session metadata scans — the likely dominant pressure source given the 2,446-session correlation

Wrapping with `try { … } finally { await handle.close() }` or porting to `fs.promises.readFile`-style auto-closing helpers should close the leak.

Workaround for affected users

Either downgrade Node to the documented 22.19+ LTS line, or prune old session JSONL files until the on-disk count is in the low hundreds.

Stability bundle excerpt (sanitized)

```json { "version": 1, "generatedAt": "2026-05-21T04:32:40.158Z", "reason": "uncaught_exception", "process": { "pid": 72273, "platform": "darwin", "arch": "arm64", "node": "25.9.0", "uptimeMs": 7208113 }, "error": { "name": "Error", "code": "ERR_INVALID_STATE", "message": "A FileHandle object was closed during garbage collection. This used to be allowed with a deprecation warning but is now considered an error. Please close FileHandle objects explicitly. File descriptor: 38 (/Users/<bot>/.openclaw/agents/main/sessions/<redacted-uuid>.jsonl.lock)" } } ```

I have 10 stability bundles over a 31h window with the same error signature (different FD / UUID each time) — happy to share more if useful.

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 - 💡(How to fix) Fix Unclosed FileHandle on session JSONL lock crashes gateway on Node ≥24 under sustained session-store load