microsoft/playwright · error · Error
page: expected Page or Frame
Error message
page: expected Page or Frame
What it means
Thrown by BrowserContext.newCDPSession(page) when the argument is neither a Page nor a Frame instance. Because the parameter type is a pseudo-union (Page|Frame) that the generic channelOwner validator cannot describe, this method does explicit instanceof checks and throws with a clear message naming the param.
Source
Thrown at packages/playwright-core/src/client/browserContext.ts:504
}
async setStorageState(storageState: string | SetStorageState): Promise<void> {
const state = await prepareStorageState(storageState);
await this._channel.setStorageState({ storageState: state }, kNoTimeout);
}
backgroundPages(): Page[] {
return [];
}
serviceWorkers(): Worker[] {
return [...this._serviceWorkers];
}
async newCDPSession(page: Page | Frame): Promise<api.CDPSession> {
// channelOwner.ts's validation messages don't handle the pseudo-union type, so we're explicit here
if (!(page instanceof Page) && !(page instanceof Frame))
throw new Error('page: expected Page or Frame');
const result = await this._channel.newCDPSession(page instanceof Page ? { page: page._channel } : { frame: page._channel }, kNoTimeout);
return CDPSession.from(result.session);
}
_onClose() {
this._closingStatus = 'closed';
this._browser?._contexts.delete(this);
this._browser?._browserType._contexts.delete(this);
this._browser?._browserType._playwright.selectors._contextsForSelectors.delete(this);
this._disposeHarRouters();
this.tracing._resetStackCounter();
this.request.tracing._resetStackCounter();
this.emit(Events.BrowserContext.Close, this);
}
async [Symbol.asyncDispose]() {
await this.close();
}View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Pass a Page or Frame from the same connection: `await context.newCDPSession(page)`.
- For worker targets use the appropriate chromium worker API, not newCDPSession.
- Ensure the object originates from the same browser/connection instance.
Example fix
// before await context.newCDPSession(worker); // after await context.newCDPSession(page);
Defensive patterns
Strategy: type-guard
Validate before calling
function isValidCdpTarget(t: unknown): boolean {
return t instanceof Page || t instanceof Frame;
}
if (!isValidCdpTarget(target))
throw new Error('newCDPSession expects a Page or Frame from the same connection.'); Type guard
function isPageOrFrame(t: unknown): t is Page | Frame {
return t instanceof Page || t instanceof Frame;
} Prevention
- Pass only Page/Frame objects obtained from the same connection.
- Avoid reusing objects across separate Playwright instances.
When it happens
Trigger: Passing a Worker, BrowserContext, JSHandle, ElementHandle, a raw channel object, or a value from a different Playwright instance into newCDPSession(). Both instanceof checks fail.
Common situations: Passing a worker reference when intending a page; mixing objects across two separate Playwright connections (each has its own class realm); passing a serialized/hand-off object.
Related errors
- Error: unable to connect to a browser that does not have any
- Please use browser.newContext()
- Connecting over CDP is only supported in Chromium and WebKit
- Passing a ConnectionTransport to connectOverCDP is not suppo
- Connecting to workers is only supported in Chromium.
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/1f5b1e6a8e37eeed.
Report an issue: GitHub.