Skip to content

[bug] host-service.js V8 OOM (~4 GB heap) under active terminal use — wedged anon_pipe_write to Electron parent, repros 1.9.6 → 1.11.1 #4868

Closed

Description

@otavio

Description

host-service.js (the Node child spawned by the Electron main) crashes with V8 FATAL ERROR: Ineffective mark-compacts near heap limit, Allocation failed - JavaScript heap out of memory after a short window of active terminal use. Immediately before the abort, the process is blocked at anon_pipe_write on an IPC pipe to its Electron parent while RSS climbs from ~500 MB to ~5 GB.

The renderer surfaces this as repeated TRPCClientError: Failed to fetch (127.0.0.1:<port>) and "frozen terminals" — the Electron UI itself stays responsive, but terminal panes never get data back.

There are actually two distinct triggers that produce the same crash signature:

  1. Cold-start trigger — large accumulated state on disk causes host-service to OOM within ~45 s of launch, before any user interaction.
  2. In-use trigger — even after the cold-start state is cleaned up, host-service still OOMs after ~2–3 min of normal terminal use.

Trigger (1) is recoverable by manual SQL surgery (described below). Trigger (2) appears to be the real underlying bug, and is what the rest of the report focuses on.

Reproduces on every Superset version I tried: 1.9.6, 1.9.7, 1.9.9, 1.11.0, 1.11.1. Not specific to the 1.11 host-service-coupling refactor (PR #4739) and not specific to Claude Code 2.1.149 (repros with 2.1.140 too).


Steps to reproduce

Trigger 1 (cold-start OOM) — reproduces on any install with a few weeks of accumulated Electric/TanStack sync history and stale terminal sessions:

  1. Use Superset normally over several weeks (multiple workspaces, many terminal sessions).
  2. Open the app on the v2 dashboard.
  3. Within ~45 s of launch, host-service.js aborts; terminals never become usable. Deterministic across relaunches and across Superset versions (state, not version, drives it).

Trigger 2 (in-use OOM) — reproduces with a freshly cleaned state:

  1. Apply the workaround in the "Workaround" section below to clear cold-start triggers.
  2. Launch Superset, open a v2 workspace.
  3. Attach to or start a terminal pane (useV2PresetExecution).
  4. Use the terminal for 2–3 minutes (any active TUI works; I used Claude Code).
  5. host-service.js accumulates outbound IPC buffer, RSS grows ~500 MB → ~5 GB, then V8 OOM-aborts. Terminals freeze, "Failed to fetch" floods renderer console.

Error output

host-service log around the abort (Trigger 1):

[terminal] respawning lost session 2e0d66b7-68ab-4199-ab26-f25e6b196e41
[terminal] respawning lost session dd6bc1d0-79ec-4933-b996-73a3cdf9b0e7
... (15+ more "respawning lost session" lines)

<--- Last few GCs --->
[498781:0x6e8001c0000]    49319 ms: Scavenge (during sweeping) 3965.2 (3975.1) -> 3965.2 (3982.1) MB
[498781:0x6e8001c0000]    52108 ms: Incremental Mark-Compact (reduce) 3967.6 (3982.1) -> 3967.6 (3970.3) MB
FATAL ERROR: Ineffective mark-compacts near heap limit
Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

host-service process state while wedged (Trigger 2), captured from /proc/<pid>:

State:  S (sleeping)
VmRSS:  5128744 kB
wchan:  anon_pipe_write

(strace requires elevated ptrace_scope on this kernel; couldn't capture the exact write(fd=…, …) payload from inside the user session. Can capture with sudo if useful.)

Coredumps generated (each one is the host-service.js child):

SIG     COREFILE   EXE                                       SIZE
SIGABRT truncated  /nix/store/.../superset-1.9.6/.../superset   1.2 GB
SIGABRT truncated  /nix/store/.../superset-1.9.9/.../superset   1.2 GB
SIGABRT truncated  /nix/store/.../superset-1.11.0/.../superset  1.2 GB
SIGABRT truncated  /nix/store/.../superset-1.11.1/.../superset  1.2 GB

Command line is consistently superset .../resources/app.asar/dist/main/host-service.js. Stack frames are stripped in the bundled binary (#0 0x… n/a (n/a + 0x0)), so the dumps mostly confirm "V8 abort()".

Renderer console at the same time:

"Failed to kill removed terminal session [object Object]"
"[useV2PresetExecution] Failed to execute preset: TRPCClientError: Failed to fetch (127.0.0.1:43681)"
"Uncaught (in promise) TRPCClientError: Failed to fetch (127.0.0.1:43681)" × N

Workaround for Trigger 1

In ~/.superset/host/<org-id>/host.db and ~/.superset/tanstack-db.sqlite:

-- host.db: terminal_sessions had 130+ rows. Even rows with status='disposed'
-- and ended_at IS NOT NULL still trigger "respawning lost session" on startup —
-- only DELETE prevents respawn (marking disposed is not enough).
DELETE FROM terminal_sessions;
-- tanstack-db.sqlite: applied_tx was 234 MB (348,998 rows) out of 247 MB total.
-- Replaying it at startup is what blows past V8's heap limit before anything else.
DELETE FROM applied_tx;
VACUUM;

After both: cold-start OOM stops; host-service launches cleanly, listens on its tRPC port, terminals open. Then Trigger 2 takes over after 2–3 min of use.


What I ruled out


Hypothesis

Trigger 2 looks like classic IPC back-pressure: host-service produces structured-clone payloads (terminal output forwarded via Electron IPC) faster than the renderer drains them. The pipe buffer (~64 KB on Linux) fills, write() blocks, and queued outbound work continues to accumulate inside the V8 heap because no drain event is being awaited. Heap grows until V8 aborts.

Possibly related: the renderer-side fixes in #3049 reduced consumer pressure. The producer (host-service) may still need a writable-side back-pressure cap or await stream.drain() on its IPC channel.

A --max-old-space-size=8192 on the host-service child would buy users more time before the abort, but it's a band-aid. The right fix is to honor IPC back-pressure on host-service's writable side, or to cap the in-memory queue size and start dropping/coalescing terminal output above a threshold.


Environment

  • OS: NixOS 26.05 (Yarara), Linux 7.0.5
  • WM: i3 / X11
  • Memory: 62 GiB total, 48 GiB available at crash
  • Superset Desktop: repros on 1.9.6, 1.9.7, 1.9.9, 1.11.0, 1.11.1
  • Electron: 40.10.0 (bundled)
  • pty-daemon: 0.2.3 / 0.2.4
  • Install: Nix derivation under /nix/store/.../superset-<ver>/

Related issues

Activity

  1. added a commit that references this issue on May 23, 2026
  2. Kitenite commented on May 23, 2026

    @Kitenite
    Member

    Thanks for the report @otavio , this is very serious and debugging with this information

  3. otavio commented on May 23, 2026

    @otavio
    Author

    I ended up reproducing it in a new environment in 1.11.1. Then I reverted to 1.9.9 in the new environment, and I couldn't reproduce it yet. In 1.11.1, when I started the new environment, I ended up with the OOM killer due to excessive memory usage, so I'm not sure if that's the same issue.

  4. Kitenite commented on May 23, 2026

    @Kitenite
    Member

    that's good to know, it may already exist before and made worse by other terminal changes. either way adding backpressure should help just reproducing and seeing if i can patch on my end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions