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
- Use the stalling context() method instead, which awaits the context promise.
- Wait for the frame's load/DOMContentLoaded lifecycle before evaluating.
- Ensure the frame is the one you expect (not a transient ad/popup iframe).
- 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
- For user-driven flows, prefer waitForLoadState before evaluating in new frames.
- Avoid the nonStalling* APIs in user code; they are internal fast-paths.
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
- Frame does not yet have the execution context
- "${part.body}" is only allowed as the first selector token,
- Selector cannot start with entering frame, select the iframe
- Selector cannot be empty when piercing frames, while parsing
- Selector cannot end with entering frame, while parsing selec
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/d44fed39a500c733.
Report an issue: GitHub.