Skip to content

[Bug]: Desktop main process SIGTRAPs during preview_open webview attach / debugger.attach #8332

Description

@bald-ai

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

Not a guaranteed crash (race). Observed sequence on macOS desktop:

  1. Desktop app has been running for hours, window in the background.
  2. Agent calls preview_status. Host is connected, but there is no tab yet: available=true, visible=false, tabId=null.
  3. Agent calls preview_open with an HTTPS URL (in this case a third-party login/deep-control page). That creates a new Loading session and mounts a <webview src=url> (including offscreen).
  4. Renderer registers the guest from did-attach / dom-ready via previewBridge.registerWebview.
  5. Main-process PreviewManager.registerWebview mutates the guest (zoom/mute/listeners) and runForks restoreControlSession → wc.debugger.attach("1.3") without waiting and without an isDestroyed() / generation gate.
  6. Overlay wait treats automation.status available=true as soon as the WebContents exists, which is before CDP attach finishes.

Related: #8221 is a generic macOS 26 periodic crash with no stack. This report is a specific CrBrowserMain SIGTRAP tied to preview open.

Expected behavior

preview_open should either succeed or return a typed automation error. The Electron main process should not abort.

Actual behavior

Main process dies with EXC_BREAKPOINT (SIGTRAP) on Thread 0 CrBrowserMain. The in-flight MCP preview_open then surfaces as:

Preview automation client <id> disconnected during open.

(PreviewAutomationClientDisconnectedError — the host stream is dropped because the app died, not because the broker race itself SIGTRAPs.)

The app relaunches afterward. The disconnect/open broker race is JS-only and is already tested; it cannot fatal-check Electron by itself.

Impact

Blocks work completely

(Hard abort of the whole desktop app, including the bundled server. Intermittent, but any cold preview_open of a new HTTPS guest can hit it.)

Version or commit

Desktop 0.0.34, Electron 41.5.0. Preview manager at fe281c540 (fix(desktop): throttle hidden preview rendering (#7445)). Captured on a personal-branded Mac build; the crashing preview attach / CDP path is unmodified upstream desktop code.

Environment

macOS 26.2 (25C56), Apple Silicon (MacBookAir10,1), T3 Code desktop wrapping the shared web client. Crash Role was Background. Process had been up ~8.6 hours.

Logs or stack traces

Exception Type:    EXC_BREAKPOINT (SIGTRAP)
Triggered by Thread: 0  CrBrowserMain
Termination Reason:  Namespace SIGNAL, Code 5, Trace/BPT trap: 5

Reliable frames (Electron Framework is stripped; large +NNNN offsets are neighboring names):
  NSApplication run
  → Electron main loop
  → node::InternalMakeCallback
  → v8::Function::Call
  → immediate crash

No Application Specific Information / CHECK text in the macOS report.

Full sanitized macOS crash report (personal bundle id removed):
https://gist.github.com/bald-ai/3d8c2a7a5d425fe743c26216ca8ffc75

Investigation (source, not a patch)

Proven:

  • Cold preview_open with a URL creates a Loading snapshot (apps/server/src/preview/Manager.ts) and ElectronBrowserHost mounts a <webview> for every session, including offscreen (apps/web/src/browser/HostedBrowserWebview.tsx).
  • Registration runs on did-attach (GuestView still attaching).
  • apps/desktop/src/preview/Manager.ts registerWebviewUnlocked calls setZoomFactor / setAudioMuted / attachListeners, then runFork(restoreControlSession).
  • ensureControlSession / restoreControlSession call debugger.attach("1.3") with no isDestroyed() check. attempt() only catches thrown JS; Chromium CHECK/ImmediateCrash is SIGTRAP on arm64.
  • Overlay available is “guest exists”, not “CDP attached” (automationStatus).
  • setWindowOpenHandler denies popups and loadURLs them into the same guest, which can navigate during attach.
  • PreviewAutomationClientDisconnectedError is raised when the host stream is removed (apps/server/src/mcp/PreviewAutomationBroker.ts). Automation subscriptions use idleTtlMs: 0.

Inferred (high): the SIGTRAP is a GuestView / DevToolsAgentHost fatal check during attach or a concurrent loadURL/setZoomFactor/debugger.attach. Exact CHECK name unknown (stripped symbols).

The broker disconnect-during-open path does not SIGTRAP. The guest-open work running at the same time can.

Likely smallest fix (not implemented here): gate debugger.attach / sendCommand / setZoomFactor / loadURL on !wc.isDestroyed() + current tab generation; await control-session attach under the tab lifecycle lock instead of runFork. Registering only on dom-ready, or attaching CDP lazily on first command that needs it, would also shrink the window. Retrying preview_open on ClientDisconnectedError would not stop the abort.

Workaround

Avoid preview_open of a new tab to an HTTPS login/redirect-heavy URL while the desktop window is in the background. Reusing an already-attached tab is much less likely to hit this. After a crash, relaunch and continue; no evidence this corrupts the sqlite store, but that is not proven.

Activity

  1. bald-ai commented on Aug 26, 2026

    @bald-ai
    Author

    This bug happened to me and agent said its not caused by my fork and fixable. So I asked it to post it here, hope it helps. If not delete, I dont care.

  2. ibniss commented on Aug 28, 2026

    @ibniss

    I hit a similar issue where t3 code crashed while the agent was using the built-in browser tools. Had my agent look into the error dump and found this issue as potentially related. I'm adding the details from my case in case they help narrow down the underlying issue, here's a summary of the investigation by 5.6 Sol:

    I hit what looks like a related preview/CDP lifecycle crash, but with a different native failure mode from the SIGTRAP reported here.

    Environment:

    • T3 Code 0.0.36-nightly.20260828.1208
    • Electron 41.5.0
    • macOS 26.2 (25C56)
    • Apple Silicon, M5
    • App role: Background
    • Process uptime before crash: about 31 minutes

    The crash was:

    Exception Type:    EXC_BAD_ACCESS (SIGSEGV)
    Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
    Termination Reason: Namespace SIGNAL, Code 11, Segmentation fault: 11
    Triggered by Thread: 0 CrBrowserMain
    

    The raw macOS report attributes the top frame to v8::Object::Set, but that is only the nearest exported symbol in the stripped Electron framework. I resolved the frame offsets against the matching Electron Breakpad symbols.

    The actual top of the stack is:

    content::DevToolsSession::DispatchProtocolNotification(...) + 0x70
    blink::mojom::DevToolsSessionHostStubDispatch::Accept(...)
    mojo::InterfaceEndpointClient::HandleIncomingMessageThunk::Accept(...)
    mojo::MessageDispatcher::Accept(...)
    mojo::InterfaceEndpointClient::HandleIncomingMessage(...)
    IPC::ChannelAssociatedGroupController...
    base::TaskAnnotator::RunTaskImpl(...)
    base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork()
    

    Electron Framework UUID / Breakpad symbol ID:

    UUID:      4C4C44A2-5555-3144-A1A4-3984082119EF
    Symbol ID: 4C4C44A255553144A1A43984082119EF0
    Top frame image offset: 0x128f1ec
    

    The faulting instructions are:

    ldr x21, [x20, #0x20]
    ...
    ldr x8, [x21]
    ldr x8, [x8, #0x10]   ; crashes reading address 0x10

    At the crash, x21 was non-null, but the first pointer loaded through it was null. Based on the symbolicated function and Chromium's DevToolsSession implementation, this appears to be the virtual call to the DevToolsAgentHostClient while dispatching an incoming protocol notification.

    My interpretation is that a CDP notification remained queued after the associated DevTools client had begun teardown or had been cleared. That would make this a later manifestation of the same preview lifecycle race described in this issue:

    • The reported SIGTRAP appears to happen during debugger.attach().
    • This SIGSEGV happens after attachment, while Chromium is delivering a protocol notification.
    • Both occur in CrBrowserMain with Electron 41.5.0 on macOS 26.2.

    If these share a root cause, checking webContents.isDestroyed() before attaching may not be sufficient by itself. The detach/dispose path may also need a generation guard or ordering that prevents queued CDP notifications from reaching a stale client.

    I can provide the full macOS crash report if useful.

    Apologies if this turns out to be unrelated, happy to move it to a separate issue and remove the comment if so.

  3. albertojb commented on Sep 3, 2026

    @albertojb

    Linux reproduction of the same SIGTRAP-in-CrBrowserMain / debugger.attach crash.

    Environment:

    • T3 Code desktop v0.0.38 (installed 2026-09-03 ~18:35 EDT, just ~9 min before crash)
    • Electron (stripped, no symbols available)
    • Linux, Omarchy (Arch)
    • Launched with --no-sandbox
    • Crash role: Foreground (not background)
    • Process uptime before crash: < 10 minutes (cold start, not hours)
    • Signal: SIGTRAP (TRAP), si_code SI_KERNEL
    • Crash thread: main thread (TID 109965), CrBrowserMain equivalent
    • ~40 other threads idle in pthread_cond_wait / epoll_wait / g_main_context_iteration (pangoft2, libglib-2.0, libdconfsettings present — Gtk build)

    Timestamp: 2026-09-03 18:44:13 EDT
    Core: coredumpctl PID 109965 (351.2M)
    Backtrace (frame 0 only, stripped): t3code + 0x8d75c91 → t3code + 0x42e1ccd → t3code + 0x4cfcbb9 → t3code + 0x7cb0567 → t3code + 0x5878c2b (no symbols)

    Different trigger from the macOS case (not preview_open of an HTTPS login page while backgrounded). Crash was on a cold start, so the likely cause is the same root issue: debugger.attach / CDP lifecycle without an isDestroyed() or generation gate hitting a Chromium CHECK/ImmediateCrash. Useful to know whether the fix gates apply to the Gtk build too.

    Filed by opencode via static-best-coding.

  4. Kabilan108 commented on Oct 6, 2026

    @Kabilan108

    Adding a Linux crash report that may be related. I authorized Codex to investigate and post this comment. The native failure appears to be in Chromium navigation-origin validation, so I am not claiming this is the same debugger.attach race as the original report.

    Environment and impact

    • T3 Code desktop AppImage 0.0.46-nightly.20261005.2676, verified from the packaged package.json.
    • NixOS 26.11, build 26.11.20261001.c59305b; Linux 6.18.54, x86_64.
    • niri/Wayland. The running renderer and GPU subprocess command lines include --ozone-platform=wayland.
    • Main-process launch argument: --password-store=gnome-libsecret. No --no-sandbox argument in the recorded main-process command line.
    • Exact Electron/Chromium versions have not been independently verified.
    • Crash at 2026-10-05 20:26:33 EDT / 2026-10-06 00:26:33 UTC.
    • Entire desktop main process terminated, rather than only a renderer or a typed preview operation failing. Main PID/TID was 11901.
    • Relaunch at 20:26:52 EDT succeeded in starting another desktop instance. The original backend remained alive and was reparented to systemd --user, matching the separate lifecycle issue [Bug]: Desktop backend outlives a crashed main process and keeps its port, so the relaunch silently moves to another port #13747. No claim about database corruption or data-loss testing.

    Observed sequence, not a deterministic repro

    The app had been running for about 68 minutes, with agent-driven embedded-preview automation active. No deliberate reproduction has been attempted against the daily profile. Window foreground/background state at the instant of the crash was not captured.

    The desktop trace records:

    1. 20:26:16.849 EDT: PreviewManager.navigate fails during navigate.normalizeUrl. The nested cause is PreviewUrlNormalizationError: Invalid preview URL (parse: https:; input length 11) and TypeError: Invalid URL. This is a recorded, handled Effect failure. It is not evidence that this exception directly caused the native crash.
    2. 20:26:16.959–16.992: requireWebContents, ensureControlSession, sendCommand, performAutomationEvaluate, automationEvaluate, and automationStatus complete successfully.
    3. 20:26:31.062–31.364: a periodic update check completes successfully and reports 0.0.46-nightly.20261005.2702 available. There is no captured evidence of update installation.
    4. 20:26:33: the kernel records a main-thread int3 trap and systemd captures a core dump.

    The exact URL/frame that was navigating when the native check failed is not yet known. A failing preview operation about 16 seconds earlier, or a successful update check about 2 seconds earlier, establishes timing, not causation.

    Native evidence

    Sanitized kernel line:

    traps: t3code[11901] trap int3 ip:646d022ace53 sp:7ffdda8c1620 error:0 in t3code[40a6e53,646d015fd000+9efd000]
    

    Systemd reports Signal: 5 (TRAP) and a present core dump, compressed size about 78.8 MiB. Its unwound main-thread frames are stripped; representative executable-relative offsets:

    #0  t3code + 0x40a7e53
    #1  t3code + 0x4f3ec20
    #2  t3code + 0x4e2c333
    #3  t3code + 0x85583cb
    #4  t3code + 0x5163fb0
    #5  t3code + 0x51633ae
    #6  t3code + 0x51ded48
    #7  t3code + 0x50cfa7b
    #8  t3code + 0x50c9e88
    #9  t3code + 0x50ce0da
    

    GDB confirms the trap instruction at executable offset 0x40a7e52, followed by ud2 at 0x40a7e53. Disassembly shows a call at 0x40a7853 to 0x3f29ca0, testing its Boolean result and branching to that trap if false:

    0x40a7853: call 0x3f29ca0
    0x40a7858: test %al,%al
    0x40a785a: je   0x40a7e52
    ...
    0x40a7e52: int3
    0x40a7e53: ud2
    

    The containing function references these diagnostic strings:

    Bug1454273-is_in_main_frame
    Bug1454273-current_origin
    Bug1454273-parent_origin
    Bug1454273-outer_doc_origin
    Bug1454273-embedder_origin
    Bug1454273-initiator_origin
    Bug1454273-initiator_relationship
    

    Those strings and the check structure match Chromium's NavigationRequest::GetOriginForURLLoaderFactoryAfterResponse(), which checks that the target renderer is permitted to commit the chosen origin through ChildProcessSecurityPolicyImpl::CanAccessOrigin(...):
    https://chromium.googlesource.com/chromium/src/+/refs/heads/main/content/browser/renderer_host/navigation_request.cc

    Inference: the crash is consistent with that navigation-origin security CHECK. This is a source/disassembly match, not a fully symbolicated stack against the exact bundled Chromium revision. GDB could not recover a useful full backtrace; the offsets above are from systemd's unwind.

    Other checks and available diagnostics

    • No matching OOM kill or GPU-reset/amdgpu error appeared in the kernel log for the inspected 20-minute window around the crash.
    • The launcher's stdout and stderr go to /dev/null. The existing desktop-main.log was historical, so it did not provide this crash's native CHECK message. Current evidence comes from the core dump, system journal, and desktop.trace.ndjson.
    • Local core and debugger output are retained. The full core is not attached publicly because it can contain credentials, browser session data, and private workspace content. Sanitized symbolication output can be supplied if maintainers specify the matching Electron symbols or another useful diagnostic.

    Is this navigation-origin CHECK best tracked here, or should it be a separate issue? A reliable reproduction and the exact failing origin remain missing.

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