Skip to content

Unattended capture: a host that loses the pipe race never listens again, and -Restart can cause it #70

Description

@wolfgang-aura

Impact: a host that starts while another host owns \\.\pipe\sourcecapsule-capture logs pipe listen failed, sends pipe_in_use to its extension, and stays connected without retrying. Nothing replaces it. The extension only logs host-status (background.js 298-302). connectNativeHost returns at once while nativePort is set (line 281), so the 30 s reconnect alarm does nothing.

When the host that owns the pipe exits, no host listens. Every CLI call then fails with ENOENT until the browser holding the idle host restarts. The CLI's error blames a browser started without the extension, and -Status says "Bridge should be available" when that browser has the flag.

The host header (lines 10-11) says a second instance "fails to listen and exits". It keeps running.

Ways to get there:

  • Two browsers run the extension. For example, Brave from the launcher plus Chrome or Edge with Load unpacked for the library-folder checks. The second one to start holds the idle host. Captures go to the first browser, with whatever flags it was started with, and stop when it closes.
  • -Restart while Chrome or Edge runs the extension. The restart block (lines 265-275) kills every SourceCapsule host on the machine, on the claim that "any surviving host is an orphan by definition". That holds only for the browser it just closed. The other browser's alarm starts a new host within 30 s, racing the restarted Brave's host. If the other browser's host wins, captures run in that browser, usually without --disable-features=CalculateNativeWinOcclusion, and threads come back as the root post alone (Unattended CLI capture publishes only the root post of a thread #5). Brave's host never takes the pipe back.
  • A fast restart where the old host has not released the pipe yet. Traced, not reproduced.

Related: Get-BrowserMainProcesses (lines 91-95) matches every main process of the same exe. So -Restart (through $running, line 182) also closes other Brave profiles, such as the chrome-devtools MCP Brave.

Where:

  • native-host/sourcecapsule-host.mjs: server.on('error') at 166-171; header comment at 10-11.
  • extension-src/background.js: connectNativeHost returns at 281; the host-status handler at 298-302.
  • scripts/start-sourcecapsule-browser.ps1: host kill at 265-275; Get-BrowserMainProcesses at 91-95; $running at 182.

Evidence: the real host and CLI on a private pipe with two stub browsers. Host A owns the pipe, host B starts, then browser A closes.

B status {"type":"sourcecapsule:host-status","ok":false,"error":"pipe_in_use"}
B still running after pipe_in_use: true
A exit code 0
after 21s: B alive true | B heartbeats sent to its browser meanwhile 1 | B host-status messages 1
raw connect to the pipe: ENOENT
CLI --ping exit 1, stdout: { "ok": false, "error": "cli_error", "message": "Cannot reach the SourceCapsule native host (ENOENT). The browser is probably running without the extension: ..." }

Host log of the same run:

2026-10-06T17:42:24.468Z listening on \\.\pipe\sc-slice4-d-1476 pid 12024
2026-10-06T17:42:24.534Z pipe listen failed: listen EADDRINUSE: address already in use \\.\pipe\sc-slice4-d-1476
2026-10-06T17:42:24.554Z browser connection gone: stdin ended - exiting so the pipe is released

The -Restart sequence with a second browser is traced from the code, not run.

Environment: main 72777ef (v1.6.8). Node on Windows, private named pipe, no browser.

Next action:

  • After EADDRINUSE, have the host retry listen every few seconds and send host-status ok:true once it owns the pipe. The remaining browser then takes over with no extension change.
  • In -Restart, stop only hosts whose parent browser is gone, and close only the main process without --user-data-dir.
  • Fix the header comment.
  • Add a case to test/native-host.test.mjs: start B while A owns the pipe, end A, and expect B to answer --ping.

Activity

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

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions