hermes - ✅(Solved) Fix TUI mode crashes with "JavaScript heap out of memory" after prolonged use [2 pull requests, 5 comments, 6 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
NousResearch/hermes-agent#12682Fetched 2026-04-20 12:17:30
View on GitHub
Comments
5
Participants
6
Timeline
8
Reactions
2
Timeline (top)
commented ×5cross-referenced ×2closed ×1

Error Message

The TUI mode (hermes --tui) crashes with a fatal Node.js OOM error after running for an extended period. The V8 heap grows to ~4GB and hits the default limit, causing an unrecoverable crash.

Error Output

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Fix Action

Fix / Workaround

Workaround

PR fix notes

PR #12822: fix(tui): guard empty idle queue drain to stop idle OOM

Description (problem / solution / changelog)

What does this PR do?

Fixes a TUI OOM that could still happen while sitting idle at the ready prompt.

The queue-drain effect in ui-tui/src/app/useMainApp.ts could still call composerActions.dequeue() when the queue was empty. In the local repro, that empty dequeue was enough to keep the idle loop churning until the TUI eventually hit a JS heap OOM.

This change adds a single guard so the drain effect returns early when composerRefs.queueRef.current.length === 0.

Related Issue

Fixes #12682

Follow-up to #12754 (fix(tui): bound retained state against idle OOM).

Type of Change

  • 🐛 Bug fix

Changes Made

  • Add an empty-queue guard to the idle queue-drain effect in ui-tui/src/app/useMainApp.ts

How to Test

  1. Run hermes --tui --dev.
  2. Let the TUI reach the normal ready state and sit idle with an empty queue.
  3. On the unpatched build, this repro OOMed locally in roughly 50-55 seconds.
  4. Apply this patch and repeat the same repro.
  5. Confirm the TUI stays up past the previous failure window.
  6. Run npm --prefix ui-tui run type-check.

Screenshots / Logs

Local repro:

  • Before: ready-state idle repro OOMed in ~50-55s
  • After: same repro stayed stable past ~15min

Changed files

  • ui-tui/src/app/useMainApp.ts (modified, +6/-1)

PR #12888: fix(tui): guard empty idle queue drain to stop idle OOM

Description (problem / solution / changelog)

TUI no longer OOMs while sitting idle at the ready prompt.

Follow-up to #12754. The queue-drain useEffect in ui-tui/src/app/useMainApp.ts could still call composerActions.dequeue() when the queue was empty, which kept the idle rerender/dequeue path alive until V8 hit its ~4GB limit (~50-55s on cresslank's repro).

Changes

  • ui-tui/src/app/useMainApp.ts: return early from the drain effect when composerRefs.queueRef.current.length === 0
  • scripts/release.py: add cresslank to AUTHOR_MAP

Validation

BeforeAfter
Idle ready (cresslank's repro)OOM at ~50-55sStable >30min
Independent confirmation (@e-shizz)crashfix
npm --prefix ui-tui run type-checkclean

Salvages #12822 (@cresslank). Authorship preserved via cherry-pick; rebase-merge.

Closes #12682.

Changed files

  • scripts/release.py (modified, +1/-0)
  • ui-tui/src/app/useMainApp.ts (modified, +6/-1)

Code Example

## Bug Description

    The TUI mode (`hermes --tui`) crashes with a fatal Node.js OOM error after running for an extended period. The V8 heap grows to ~4GB and hits the default limit, causing an unrecoverable crash.

    ## Error Output

---

## Environment

    - **Hermes version:** v0.10.0 (2026.4.16)
    - **Node.js:** v22.22.0
    - **OS:** WSL2 (Ubuntu) on Windows
    - **TUI framework:** Ink (React) at `ui-tui/`

    ## Observations

    - Heap grows to **4043 MB** (~4 GB, the default V8 limit) over time
    - `average mu = 0.100`GC retention rate of only 10%, meaning GC is largely ineffective
    - The `Mark-Compact` collector runs repeatedly but fails to free meaningful memory
    - This suggests a memory leak in the TUI layer, likely in one of:
      - Message/history accumulation in `app.tsx` or `useVirtualHistory`
      - Tool output rendering in the Ink component tree
      - The `gatewayClient.ts` JSON-RPC message buffer

    ## Workaround

    Setting a larger heap limit delays the crash:

---

But this is only a temporary fix — the underlying leak persists.

    ## Suggested Fix

    Investigate memory retention in the TUI React component tree. Potential areas:
    1. Cap the virtual history buffer size and prune old entries
    2. Ensure tool result objects are not retained after rendering
    3. Consider periodic forced GC or component unmount for long sessions
RAW_BUFFERClick to expand / collapse
    ## Bug Description

    The TUI mode (`hermes --tui`) crashes with a fatal Node.js OOM error after running for an extended period. The V8 heap grows to ~4GB and hits the default limit, causing an unrecoverable crash.

    ## Error Output

    ```
    <--- Last few GCs --->

    [78512:0x3f9a3000]   254462 ms: Mark-Compact 4042.1 (4130.1) -> 4029.0 (4130.9) MB, pooled: 2 MB, 1048.69 / 1.36 ms  (average mu = 0.126, current mu = 0.076) task; scavenge might not succeed
    [78512:0x3f9a3000]   255635 ms: Mark-Compact 4043.1 (4131.1) -> 4030.0 (4131.9) MB, pooled: 1 MB, 1088.52 / 1.23 ms  (average mu = 0.100, current mu = 0.072) task; scavenge might not succeed

    <--- JS stacktrace --->

    FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
    ----- Native stack trace -----

     1: 0xe40d24 node::OOMErrorHandler [/usr/bin/node]
     2: 0x1216be0 v8::Utils::ReportOOMFailure [/usr/bin/node]
     3: 0x1216eb7 v8::internal::V8::FatalProcessOutOfMemory [/usr/bin/node]
     ...
    ```

    ## Environment

    - **Hermes version:** v0.10.0 (2026.4.16)
    - **Node.js:** v22.22.0
    - **OS:** WSL2 (Ubuntu) on Windows
    - **TUI framework:** Ink (React) at `ui-tui/`

    ## Observations

    - Heap grows to **4043 MB** (~4 GB, the default V8 limit) over time
    - `average mu = 0.100` — GC retention rate of only 10%, meaning GC is largely ineffective
    - The `Mark-Compact` collector runs repeatedly but fails to free meaningful memory
    - This suggests a memory leak in the TUI layer, likely in one of:
      - Message/history accumulation in `app.tsx` or `useVirtualHistory`
      - Tool output rendering in the Ink component tree
      - The `gatewayClient.ts` JSON-RPC message buffer

    ## Workaround

    Setting a larger heap limit delays the crash:
    ```bash
    export NODE_OPTIONS="--max-old-space-size=8192"
    ```

    But this is only a temporary fix — the underlying leak persists.

    ## Suggested Fix

    Investigate memory retention in the TUI React component tree. Potential areas:
    1. Cap the virtual history buffer size and prune old entries
    2. Ensure tool result objects are not retained after rendering
    3. Consider periodic forced GC or component unmount for long sessions
    ```

extent analysis

TL;DR

The most likely fix involves addressing the memory leak in the TUI layer by investigating and optimizing memory retention in the React component tree, specifically in areas such as the virtual history buffer, tool result objects, and potentially implementing periodic forced GC or component unmount for long sessions.

Guidance

  • Investigate the app.tsx and useVirtualHistory components for potential memory leaks due to unbounded message/history accumulation.
  • Review the Ink component tree for unnecessary retention of tool output rendering data.
  • Consider implementing a cap on the virtual history buffer size and a mechanism to prune old entries to prevent indefinite growth.
  • Ensure that tool result objects are properly released after rendering to prevent memory retention.

Example

No specific code example can be provided without further details, but a potential optimization could involve implementing a mechanism to limit the size of the virtual history buffer, such as:

const MAX_HISTORY_SIZE = 1000;
// ...
useVirtualHistory((history) => {
  if (history.length > MAX_HISTORY_SIZE) {
    history.slice(0, MAX_HISTORY_SIZE);
  }
  // ...
});

This is a highly simplified example and actual implementation would depend on the specifics of the useVirtualHistory hook and the requirements of the application.

Notes

The provided workaround of increasing the Node.js heap limit is temporary and does not address the underlying memory leak. A thorough investigation of the React component tree and related components is necessary to identify and fix the root cause of the memory leak.

Recommendation

Apply a workaround by increasing the heap limit as a temporary measure while investigating the memory leak, but prioritize addressing the underlying issue by optimizing memory retention in the TUI React component tree.

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