{"record":{"id":"9f8f12165b655b16","repo":"can1357/oh-my-pi","slug":"browser-websocket-endpoint-is-unavailable","errorCode":null,"errorMessage":"Browser websocket endpoint is unavailable","messagePattern":"Browser websocket endpoint is unavailable","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/tab-supervisor.ts","lineNumber":772,"sourceCode":"\t\tif (await releaseTab(name, opts)) count++;\n\t}\n\treturn count;\n}\n\n/** Test-only accessor for the module-global tabs map. */\nexport function getTabsMapForTest(): ReadonlyMap<string, TabSession> {\n\treturn tabs;\n}\n\nfunction isLastSurfaceCloseError(err: unknown): boolean {\n\tconst message = err instanceof Error ? err.message : String(err);\n\treturn /last/i.test(message);\n}\n\nasync function buildInitPayload(browser: PuppeteerBrowserHandle, opts: AcquireTabOptions): Promise<WorkerInitPayload> {\n\tconst safeDir = getPuppeteerDir();\n\tconst browserWSEndpoint = browser.browser.wsEndpoint();\n\tif (!browserWSEndpoint) throw new ToolError(\"Browser websocket endpoint is unavailable\");\n\tif (browser.kind.kind === \"headless\") {\n\t\treturn {\n\t\t\tmode: \"headless\",\n\t\t\tbrowserWSEndpoint,\n\t\t\tsafeDir,\n\t\t\t// Visible launches still need an OMP-owned page, stealth setup, and\n\t\t\t// independent lifecycle; only their fixed device emulation is disabled.\n\t\t\temulateViewport: browser.kind.headless,\n\t\t\tviewport: opts.viewport,\n\t\t\tdialogs: opts.dialogs,\n\t\t\turl: opts.url,\n\t\t\twaitUntil: opts.waitUntil,\n\t\t\ttimeoutMs: opts.timeoutMs,\n\t\t};\n\t}\n\t// Connected and relay browsers are user-driven. When no target is requested,\n\t// adopt the visible tab and avoid raising it before screenshots. An explicit\n\t// target may be backgrounded, so retain activation for target-correct pixels.","sourceCodeStart":754,"sourceCodeEnd":790,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/tab-supervisor.ts#L754-L790","documentation":"buildInitPayload reads the Puppeteer browser's WebSocket endpoint (browser.wsEndpoint()) to hand it to the tab worker. If the endpoint is absent the browser was not launched with a WS listener (or is already disconnected), so the worker cannot attach and a ToolError is thrown.","triggerScenarios":"Browser handle launched without a websocket endpoint (e.g. launched with pipe transport), the browser process exited/died before the worker attached, or the handle references a disconnected browser instance.","commonSituations":"Browser crashed between launch and worker spawn; browser launched with browserWSEndpoint disabled / pipe mode; reusing a stale handle after the process was killed; resource limits (OOM) killing Chrome at startup.","solutions":["Verify the browser process is running and was launched with a WS endpoint; close and relaunch the browser.","Re-open the tab — a fresh acquire will relaunch a healthy browser if the old one died.","Check system resources/logs for Chrome startup crashes (OOM, missing sandbox flags).","Ensure nothing in the environment forces pipe transport or disables the DevTools WS listener."],"exampleFix":"// before\nconst stale = getBrowserHandle(); // process died\nawait openTab(stale); // wsEndpoint() empty\n// after\nawait closeBrowser(stale, { kill: true });\nconst tab = await openTab({ name: \"docs\", url }); // relaunches browser with WS endpoint","handlingStrategy":"try-catch","validationCode":"const ep = handle.browser.wsEndpoint();\nif (!ep || !handle.browser.connected) {\n  await relaunchBrowser();\n}","typeGuard":"function hasWsEndpoint(b: { wsEndpoint(): string | undefined; connected: boolean }): boolean {\n  return b.connected && typeof b.wsEndpoint() === \"string\" && b.wsEndpoint().length > 0;\n}","tryCatchPattern":"try {\n  await openTab(handle);\n} catch (e) {\n  if (e instanceof ToolError && e.message === \"Browser websocket endpoint is unavailable\") {\n    await closeBrowser(handle, { kill: true });\n    return openTab(freshHandle()); // relaunch\n  }\n  throw e;\n}","preventionTips":["Launch the browser with a WS (DevTools) listener, not pipe-only transport","Check browser.connected before reuse of long-lived handles","Monitor for Chrome startup crashes (OOM, missing flags) in logs"],"tags":["browser","websocket","puppeteer"],"backgroundTag":"websocket-endpoint-unavailable","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}