Skip to content

X archive crashes the browser process with SIGSEGV #721

Open

Description

@micahflee

Archiving X tweets with HTML saving enabled kills the Electron browser process with SIGSEGV. The app disappears with no error dialog, no JS exception, and no entry in main.log — the log simply stops mid-line.

Reproduced 9 times on 2026-09-21. Every run dies; only when varies.

Environment

Reproduction

  1. Add an X account and build the local database.
  2. Run an archive job with "save HTML of tweets" enabled.
  3. It saves some number of tweets, then the process vanishes.

Tweets completed before the crash, across runs: 4, 3, 12, 21, 28, 0. Not the same tweet each time, so it is not one malformed page.

The crash

SIGSEGV, si_code: SEGV_MAPERR, on the main thread of the browser process. Stack traces are identical across every coredump checked (PIDs 192362, 205530, 207521), frame for frame through #10:

#0  0x6936408  #1  0x98d99eb  #2  0x625e222  #3  0x625e75e
#4  0x63746f2  #5  0x62d3b46  #6  0x62ce5f6  #7  0x62cf662
#8  0x62cf4ff  #9  0x62d04f2  #10 0x357e416

(offsets into node_modules/electron/dist/electron; unsymbolized — the shipped binary has no symbols)

Frames below #10 are the glib message pump, so it dies running a task off the main loop. gdb shows V8-heap return addresses under #0, so it is native code reached from JS.

Coredumps are in coredumpctl on the reporting machine (coredumpctl list → 2026-09-21, 9 × SIGSEGV on .../cyd/node_modules/electron/dist/electron).

Where it dies

Traced with fs.appendFileSync instrumentation in archive:savePage plus ipcMain.handle and webContents lifecycle wrappers. electron-log is no use here — it buffers and loses the final line.

The last full save cycle completes cleanly:

19:57:36.155  enter basename=...977144528934 webContentsID=2
19:57:36.155  got wc destroyed=false crashed=false loading=false
19:57:36.165  post savePage bytes=136790
19:57:36.382  post convert
19:57:36.384  post serialize chars=145855
19:57:36.385  post write
19:57:36.385  done

It then dies in the gap between tweets. The last trace lines before death:

19:57:36.601  WC2 did-start-navigation .../status/2102090040113602812
19:57:36.676  WC2 did-start-navigation  (same URL, second time)
19:57:36.766  WC2 did-stop-loading
19:57:36.930  WC2 did-stop-loading
19:57:36.968  IPC> X:isRateLimited
19:57:36.971  IPC< X:isRateLimited
<dead>

After X:isRateLimited the renderer runs sleep(200), doesSelectorExist, waitForSelector — all webview.executeJavaScript, which does not go through ipcMain and so leaves no trace. The crash is inside that window.

Note the doubled did-start-navigation / did-stop-loading on every URL: X's SPA navigates again immediately after the load completes.

Ruled out

  • Not webContents.savePage — the MHTML is written, 136,790 bytes.
  • Not mhtml2html / jsdom — convert and serialize both complete and the HTML lands on disk. (Root jsdom is 29.1.1 on both main and the branch; archive.ts passes its own parseDOM, so the conversion path is unchanged.)
  • Not memory — RSS flat at ~472–510 MB across 21 tweets, heap oscillating 60–92 MB. No growth.
  • Not a dying helper process — child-process-gone and render-process-gone handlers never fire before the segfault.
  • Not content-specific — different tweet every run.

Probably the same bug: login hangs forever

With a fresh profile, login sticks on "I'm discovering your username and profile picture...". graphqlGetViewerUser (src/renderer/src/view_models/XViewModel/graphql.ts) does:

20:06:36.395  IPC> X:getCookie
20:06:36.402  IPC< X:getCookie        <- ct0 fetched fine
20:06:36.404  IPC> X:resetRateLimitInfo
20:06:36.617  WC3 did-start-navigation https://x.com/home
20:06:37.254  IPC> X:isRateLimited
20:06:37.256  IPC< X:isRateLimited
<hung 77 seconds until the app was quit>

The next statement is webview.executeJavaScript running a fetch that carries AbortSignal.timeout(5000) and a catch returning null, so it cannot legitimately exceed ~5s. The promise never settled.

Same shape as the crash: an executeJavaScript issued on the webview shortly after a navigation. One symptom is a hang, the other a segfault.

Also seen once each, possibly related: Error: Invalid guestInstanceId: 2 out of WebViewElement.disconnectedCallback, and Network service crashed or was terminated, restarting service.

Tried, did not fix it

BrowserViewModel.loadURL called this.sleep(2000) without await, dropping a deliberate post-navigation settle described by its own comment ("Sleep 2 seconds after loading each URL, to make everything more stable"). Three sibling sites had the same defect. That is a genuine bug and worth fixing on its own merits, but it does not fix this crash — restoring the settle produced a byte-identical stack.

Lead worth following

Adding an awaited IPC round-trip immediately before and after every executeJavaScript (as instrumentation) let a full 53-tweet archive complete. That points at a race rather than deterministic corruption — but it is one run, and the crash point varies enough that it is suggestive rather than conclusive.

executeJavaScript also has no timeout anywhere in the codebase, which is why the login hang froze the job indefinitely instead of erroring. Worth having regardless of the root cause.

Symbolizing electron + 0x6936408 against Electron 44.4.3's published debug symbols would turn the stack above into a function name and is the obvious next step for whoever picks this up.

Note for agents

This cannot be reproduced by an agent: Electron renderers will not start in the sandboxed shell (Chromium is blocked from shared memory in both /dev/shm and /tmp, and --disable-dev-shm-usage does not help). Instrument, then have a human run it.

(This was written by an LLM.)

Activity

  1. h0us3c4ll commented on Sep 25, 2026

    @h0us3c4ll

    i have same issue . but after 3th try , it suddenly works . BUT : cyd has wrong amount of my (re)tweets , it has 500 , but i have +1000 . fyi

    edit : it worked after i use "ulimit -c unlimited"

  2. h0us3c4ll commented on Sep 25, 2026

    @h0us3c4ll

    it also crash again , with :

    10:20:16.639 › XAccountController.deleteTweetsCountNotArchived
    (node:9602) [DEP0169] DeprecationWarning: url.parse() behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for url.parse() vulnerabilities.
    10:20:33.730 › XAccountController.deleteTweetsStart
    [9679:0925/165150.607236:ERROR:components/viz/service/display/display.cc:271] Frame latency is negative: -0.042 ms
    Segmentation fault (core dumped)

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions