Skip to content

v3 CUA: CDP -32000 "Cannot find context" race condition during page navigation #1778

@robert-onyango-avenu

Description

@robert-onyango-avenu

Environment Information

Stagehand:

  • Language/SDK: TypeScript
  • Stagehand version: 3.1.0
  • Node: v22.x
  • Browser: Chromium via Browserbase

AI Provider:

  • Provider: Anthropic
  • Model: claude-sonnet-4-20250514

Issue Description

Stagehand's v3 CUA understudy CDP module throws unhandled rejections with -32000 Cannot find context with specified id during full-page navigations. The error originates from CdpConnection.onMessage in v3/understudy/cdp.ts when the CDP module sends a command targeting a JavaScript execution context that was destroyed by a page reload.

Stack Trace

Error: -32000 Cannot find context with specified id
    at CdpConnection.onMessage (stagehand/lib/v3/understudy/cdp.ts:210:20)
    at WebSocket.<anonymous> (stagehand/lib/v3/understudy/cdp.ts:100:42)

Root Cause

During full-page reloads (especially in legacy server-rendered apps like Apache Struts), JavaScript execution contexts are destroyed and recreated by the browser. If the CDP module sends a command (e.g., Runtime.evaluate) targeting a context ID that was already destroyed by the navigation, Chrome responds with -32000 Cannot find context with specified id.

This is a race condition between:

  1. Stagehand's CDP module holding a reference to an execution context ID
  2. The browser destroying that context during a full-page navigation
  3. The CDP module sending a command to the stale context before it learns about the destruction

Frequency

In our test suite against an Apache Struts 1.3.10 app, this error causes our tests to fail as much as 50% of the time.

The app performs full-page reloads on form submissions and menu navigation (server-side rendered HTML, no SPA routing), which triggers this race condition much more frequently than typical modern web apps.

Reproduction

  1. Use Stagehand v3 with Browserbase against a server-rendered app that does full-page reloads (not SPA navigation)
  2. Perform a multi-step agent task that spans multiple page navigations
  3. The -32000 error appears as an unhandled rejection during or immediately after a page reload

Expected Behavior

The CDP module should gracefully handle stale execution context IDs:

  • Detect when a context ID is no longer valid (e.g., after receiving a Runtime.executionContextDestroyed event)
  • Retry the command with the new context ID, or
  • Throw a retriable error that the agent loop can handle cleanly

Current Workaround

We register a persistent process.on('unhandledRejection') handler that catches CDP errors and prevents process crashes:

process.on('unhandledRejection', (reason: unknown) => {
  const isCdpError = reason instanceof Error &&
    (reason.message?.includes('Cannot find context with specified id') ||
     reason.message?.includes('Session with given id not found') ||
     reason.message?.includes('Target closed') ||
     reason.message?.includes('Protocol error'));
  if (isCdpError) {
    console.warn(`[CDP] Non-fatal rejection caught: ${(reason as Error).message}`);
    return;
  }
  throw reason;
});

This prevents Node.js crashes but cannot prevent the test action from failing — by the time the rejection fires, the CDP command has already failed and the agent step throws.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions