microsoft/playwright · error · Error

CDP connections are only supported by Chromium

Error message

CDP connections are only supported by Chromium

What it means

connectOverCDP is a method on the abstract BrowserType base class whose default implementation throws this error. Only the Chromium subclass overrides it; Firefox and WebKit inherit the throwing stub, so calling chromium-only CDP attachment on those browser types is rejected.

Source

Thrown at packages/playwright-core/src/server/browserType.ts:288

        const log = helper.formatBrowserLogs(browserLogsCollector.recentLogs());
        const updatedLog = this.doRewriteStartupLog(log);
        throw new Error(`Failed to launch the browser process.\nBrowser logs:\n${updatedLog}`);
      }
      if (!this.supportsPipeTransport(options)) {
        transport = await WebSocketTransport.connect(progress, wsEndpoint!);
      } else {
        const stdio = launchedProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
        transport = new PipeTransport(stdio[3], stdio[4]);
      }
      return { browserProcess, artifactsDir: prepared.artifactsDir, userDataDir: prepared.userDataDir, transport, wsEndpoint };
    } catch (error) {
      await progress.race(closeOrKill(DEFAULT_PLAYWRIGHT_TIMEOUT).catch(() => {}));
      throw error;
    }
  }

  async connectOverCDP(progress: Progress, params: channels.BrowserTypeConnectOverCDPParams): Promise<Browser> {
    throw new Error('CDP connections are only supported by Chromium');
  }

  async connectToWorker(progress: Progress, endpoint: string): Promise<Worker> {
    throw new Error('CDP connections are only supported by Chromium');
  }

  async launchWithSeleniumHub(progress: Progress, hubUrl: string, options: types.LaunchOptions): Promise<Browser> {
    throw new Error('Connecting to SELENIUM_REMOTE_URL is only supported by Chromium');
  }

  private _validateLaunchOptions(options: types.LaunchOptions): types.LaunchOptions {
    let { headless = true, downloadsPath, proxy } = options;
    if (debugMode() === 'inspector')
      headless = false;
    if (downloadsPath && !path.isAbsolute(downloadsPath))
      downloadsPath = path.join(process.cwd(), downloadsPath);
    if (options.socksProxyPort)
      proxy = { server: `socks5://127.0.0.1:${options.socksProxyPort}` };

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Use chromium.connectOverCDP(endpoint) — CDP is a Chromium DevTools protocol.
  2. If you need a non-Chromium browser, use launch()/connect() over the Playwright WebSocket server instead of CDP.
  3. Branch on browserType: only call connectOverCDP when the type is chromium.

Example fix

// before
const b = await firefox.connectOverCDP('http://localhost:9222');
// after
const b = await chromium.connectOverCDP('http://localhost:9222');
Defensive patterns

Strategy: type-guard

Validate before calling

function canConnectOverCDP(browserType: { name: string }): boolean {
  return browserType.name === 'chromium';
}

Type guard

function isChromium(bt: any): boolean {
  return bt?.name === 'chromium' || bt === chromium;
}

Prevention

When it happens

Trigger: await firefox.connectOverCDP(endpoint) or await webkit.connectOverCDP(endpoint) — only chromiumBrowserType overrides connectOverCDP.

Common situations: Generic code that picks a browserType by config and unconditionally calls connectOverCDP. Copy-pasting a Chromium CDP snippet and pointing it at firefox/webkit.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/e204add699778aba. Report an issue: GitHub.