chenglou/pretext · error · Error

${session.message ?? session.error}

Error message

${session.message ?? session.error}

What it means

Thrown during Firefox session initialization when the WebDriver BiDi 'session.new' command returns an error object. The BiDi client surfaces protocol-level errors as { error, message }; this throw picks message when present, else the error code. It means Firefox accepted the TCP connection (waitForPort passed) but its BiDi endpoint rejected session creation — typically a capability or version problem.

Source

Thrown at scripts/browser-automation.ts:381

    '--profile',
    profileDir,
    '--remote-debugging-port',
    String(bidiPort),
    'about:blank',
  ], {
    cwd: process.cwd(),
    stdio: 'ignore',
  })

  let bidi: FirefoxBidiClient | null = null

  try {
    await waitForPort(bidiPort)
    bidi = await connectFirefoxBidi(bidiPort)

    const session = await bidi.send('session.new', { capabilities: { alwaysMatch: {} } })
    if (session.error !== undefined) {
      throw new Error(session.message ?? session.error)
    }

    const tree = await bidi.send('browsingContext.getTree', {})
    if (tree.error !== undefined) {
      throw new Error(tree.message ?? tree.error)
    }

    const contexts = (tree.result as { contexts: Array<{ context: string }> }).contexts
    const context = contexts[0]?.context
    if (context === undefined) {
      throw new Error('Firefox BiDi returned no browsing context')
    }

    return {
      bidi,
      context,
      firefoxProcess,
      profileDir,

View on GitHub (pinned to ac49b09b7d)

Solutions

  1. Upgrade Firefox to a recent release with full WebDriver BiDi support.
  2. Launch Firefox manually with the same flags (--headless --new-instance --remote-debugging-port <port>) and check about:debugging / the console for capability errors.
  3. Clear the profile dir and let the script create a fresh one.
  4. Read the exact message field — it usually names the unsupported capability or version mismatch.
Defensive patterns

Strategy: fallback

Validate before calling

// Verify Firefox supports WebDriver BiDi before launching.
// (No runtime API; check the installed version against Mozilla's BiDi minimum.)
import { execFileSync } from 'node:child_process'
const ver = execFileSync('/Applications/Firefox.app/Contents/MacOS/firefox', ['--version'], { encoding: 'utf8' })
if (Number.parseInt(ver.match(/(\d+)\./)?.[1] ?? '0', 10) < 113) {
  throw new Error('Firefox >= 113 required for WebDriver BiDi')
}

Type guard

function isBidiError(reply: { error?: unknown, message?: unknown }): boolean {
  return reply.error !== undefined
}

Try / catch

// initializeFirefoxSession already cleans up Firefox on this error; the caller should retry once.
try {
  session = await initializeFirefoxSession()
} catch (error) {
  // one retry for transient capability negotiation failures
  session = await initializeFirefoxSession()
}

Prevention

When it happens

Trigger: Firefox BiDi session.new returns { error: '...', message: '...' } — capability alwaysMatch:{} unsupported by the installed Firefox version; Firefox too old to support BiDi; the remote-debugging-port is a legacy Marionette endpoint rather than BiDi; profile incompatibility.

Common situations: Firefox version predates WebDriver BiDi support (need a recent version); a Firefox update changed BiDi capability negotiation; a corrupted profile passed via --profile; conflicting Marionette/RemoteProtocol flags.

Related errors


AI-assisted analysis of chenglou/pretext@ac49b09b7d (2026-08-12). Data as JSON: /api/errors/c1483e5b3896e7e7. Report an issue: GitHub.