stablyai/orca · error · Error

Could not attach debugger. DevTools may already be open for

Error message

Could not attach debugger. DevTools may already be open for this tab.

What it means

Thrown when CdpWsProxy.attachDebugger() cannot acquire the Electron CDP debugger on a WebContents. The underlying acquireElectronDebugger() either fails to call webContents.debugger.attach('1.3') (the tab is destroyed, DevTools already holds the session, or a prior attach errored), so the catch wraps any failure into this user-facing message. A WebContents only permits one debug protocol attachment at a time; a second consumer is rejected by Electron.

Source

Thrown at src/main/browser/cdp-ws-proxy.ts:220

            id: 'orca-proxy-target',
            webSocketDebuggerUrl: `ws://127.0.0.1:${this.port}`
          }
        ])
      )
      return
    }
    res.writeHead(404)
    res.end()
  }

  private async attachDebugger(): Promise<void> {
    if (this.attached) {
      return
    }
    try {
      this.debuggerLease = acquireElectronDebugger(this.webContents)
    } catch {
      throw new Error('Could not attach debugger. DevTools may already be open for this tab.')
    }
    this.attached = true

    // Why: attaching the CDP debugger sets navigator.webdriver = true and
    // exposes other automation signals that Cloudflare Turnstile checks.
    // Inject before any page loads so challenges succeed.
    try {
      await this.webContents.debugger.sendCommand('Page.enable', {})
      await this.webContents.debugger.sendCommand('Page.addScriptToEvaluateOnNewDocument', {
        source: ANTI_DETECTION_SCRIPT
      })
    } catch {
      /* best-effort — page domain may not be ready yet */
    }

    this.debuggerMessageHandler = (_event: unknown, ...rest: unknown[]) => {
      const [method, params, sessionId] = rest as [
        string,

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Close any open DevTools window on the target tab and retry the operation.
  2. Ensure CdpWsProxy.stop() / detachDebugger() ran from the previous session before starting a new one.
  3. Check webContents.isDestroyed() before attaching and skip/teardown if true.
  4. Coordinate all CDP consumers through the ElectronDebuggerLease ref-count so only one attach path exists.

Example fix

// before
try {
  this.debuggerLease = acquireElectronDebugger(this.webContents)
} catch {
  throw new Error('Could not attach debugger. DevTools may already be open for this tab.')
}

// after
if (this.webContents.isDestroyed()) {
  throw new Error('Browser tab is no longer available')
}
if (this.webContents.debugger.isAttached()) {
  throw new Error('Could not attach debugger. DevTools may already be open for this tab.')
}
this.debuggerLease = acquireElectronDebugger(this.webContents)
Defensive patterns

Strategy: validation

Validate before calling

// Run before CdpWsProxy.start()
function canAttachDebugger(webContents: WebContents): boolean {
  return !webContents.isDestroyed() && !webContents.debugger.isAttached()
}
if (!canAttachDebugger(this.webContents)) {
  throw new Error('DevTools or another debugger is already attached.')
}

Prevention

When it happens

Trigger: Calling CdpWsProxy.start() on a tab where DevTools is already open (F12), calling start() twice without stop(), attaching after the WebContents was destroyed, or another internal consumer (e.g. a screenshot/PDF helper) already holding the debugger lease and crashing without releasing it.

Common situations: User opens DevTools manually on the agent browser tab and then triggers a CDP-driven action (screenshot, print-to-pdf, automation). A previous CdpWsProxy crashed mid-session leaving the debugger attached. CI runs that launch headless automation while a DevTools window is docked.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/0633d607a7203497. Report an issue: GitHub.