microsoft/playwright · warning · Error

Frame does not yet have a main execution context

Error message

Frame does not yet have a main execution context

What it means

nonStallingRawEvaluateInExistingMainContext needs a main (page) execution context that already exists (non-blocking). If the frame has not yet received its main context - e.g. right after attachment or before first commit - it throws 'Frame does not yet have a main execution context'.

Source

Thrown at packages/playwright-core/src/server/frames.ts:626

      throw new EvaluationStalledError('Open JavaScript dialog prevents evaluation');

    const promise = new ManualPromise<T>();
    this._raceAgainstEvaluationStallingEventsPromises.add(promise);
    try {
      return await Promise.race([
        cb(),
        promise
      ]);
    } finally {
      this._raceAgainstEvaluationStallingEventsPromises.delete(promise);
    }
  }

  nonStallingRawEvaluateInExistingMainContext(expression: string): Promise<any> {
    return this.raceAgainstEvaluationStallingEvents(() => {
      const context = this.existingContext('main');
      if (!context)
        throw new Error('Frame does not yet have a main execution context');
      return context.rawEvaluateJSON(expression);
    });
  }

  nonStallingEvaluateInExistingContext(expression: string, world: types.World): Promise<any> {
    return this.raceAgainstEvaluationStallingEvents(() => {
      const context = this._contextData.get(world)?.context;
      if (!context)
        throw new Error('Frame does not yet have the execution context');
      return context.evaluateExpression(expression, { isFunction: false });
    });
  }

  _recalculateNetworkIdle(frameThatAllowsRemovingNetworkIdle?: Frame) {
    let isNetworkIdle = this._firedNetworkIdleSelf;
    for (const child of this._childFrames) {
      child._recalculateNetworkIdle(frameThatAllowsRemovingNetworkIdle);
      // We require networkidle event to be fired in the whole frame subtree, and then consider it done.

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Use the stalling context() method instead, which awaits the context promise.
  2. Wait for the frame's load/DOMContentLoaded lifecycle before evaluating.
  3. Ensure the frame is the one you expect (not a transient ad/popup iframe).
  4. Retry after a short waitForFunction on the page-level context.

Example fix

// before: existing-context call on a fresh iframe
const result = await frame.nonStallingRawEvaluate(...); // throws
// after: await the context
await frame.context('main');
// or wait for load
await frame.waitForLoadState?.('domcontentloaded');
Defensive patterns

Strategy: validation

Validate before calling

// Wait for the main context before evaluating
await page.frameLocator(selector).locator('body').waitFor();
// then operate

Type guard

// Guard: does the frame expose a context yet?
function hasMainContext(frame: any): boolean {
  return !!frame._contextData?.get('main')?.context;
}

Try / catch

null

Prevention

When it happens

Trigger: Running an evaluation that uses the 'existing context' (non-stalling) path on a frame that has not yet had its main world context created: freshly attached iframes, about:blank before commit, or frames mid-navigation before the new document's context is ready.

Common situations: Acting on a just-added iframe before DOMContentLoaded; cross-frame helper calls during rapid navigations; evaluations triggered from page event handlers that fire before the context is attached; timing-sensitive tests on slow CI.

Related errors


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