{"record":{"id":"accac594d5bbaa1e","repo":"microsoft/playwright","slug":"cdp-session-must-be-initiated-with-either-page-or","errorCode":null,"errorMessage":"CDP session must be initiated with either Page or Frame, not none or both","messagePattern":"CDP session must be initiated with either Page or Frame, not none or both","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts","lineNumber":380,"sourceCode":"  async disableRecorder(params: channels.BrowserContextDisableRecorderParams, progress: Progress): Promise<void> {\n    const recorder = await progress.race(Recorder.existingForContext(this._context));\n    if (recorder)\n      await progress.race(recorder.setMode('none'));\n  }\n\n  async exposeConsoleApi(params: channels.BrowserContextExposeConsoleApiParams, progress: Progress): Promise<void> {\n    await this._context.exposeConsoleApi(progress);\n  }\n\n  async pause(params: channels.BrowserContextPauseParams, progress: Progress) {\n    // Debugger will take care of this.\n  }\n\n  async newCDPSession(params: channels.BrowserContextNewCDPSessionParams, progress: Progress): Promise<channels.BrowserContextNewCDPSessionResult> {\n    if (this._object._browser.options.browserType !== 'chromium')\n      throw new Error(`CDP session is only available in Chromium`);\n    if (!params.page && !params.frame || params.page && params.frame)\n      throw new Error(`CDP session must be initiated with either Page or Frame, not none or both`);\n    const crBrowserContext = this._object as CRBrowserContext;\n    return { session: new CDPSessionDispatcher(this, await progress.race(crBrowserContext.newCDPSession((params.page ? params.page as PageDispatcher : params.frame as FrameDispatcher)._object))) };\n  }\n\n  async clockFastForward(params: channels.BrowserContextClockFastForwardParams, progress: Progress): Promise<channels.BrowserContextClockFastForwardResult> {\n    await progress.race(this._context.clock.fastForward(params.ticksString ?? params.ticksNumber ?? 0));\n  }\n\n  async clockInstall(params: channels.BrowserContextClockInstallParams, progress: Progress): Promise<channels.BrowserContextClockInstallResult> {\n    await progress.race(this._context.clock.install(params.timeString ?? params.timeNumber ?? undefined));\n  }\n\n  async clockPauseAt(params: channels.BrowserContextClockPauseAtParams, progress: Progress): Promise<channels.BrowserContextClockPauseAtResult> {\n    await progress.race(this._context.clock.pauseAt(params.timeString ?? params.timeNumber ?? 0));\n    this._clockPaused = true;\n  }\n\n  async clockResume(params: channels.BrowserContextClockResumeParams, progress: Progress): Promise<channels.BrowserContextClockResumeResult> {","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts#L362-L398","documentation":"Thrown by BrowserContextDispatcher.newCDPSession() when the params do not contain exactly one of page or frame. The server requires precisely one target handle: either neither is set (no target) or both are set (ambiguous) is rejected. The public client API always passes a single Page, so this fires mainly from low-level protocol misuse or custom clients.","triggerScenarios":"Sending the newCDPSession RPC with both params.page and params.frame populated, or with neither. Happens with hand-rolled protocol clients, buggy serializers that duplicate a handle into both fields, or code that builds the params object conditionally and ends up with both branches setting a value.","commonSituations":"Custom transport/protocol clients built on playwright-core; rare in normal usage because the typed client API (page -> newCDPSession) always supplies exactly one target.","solutions":["Pass exactly one target: use the public context.newCDPSession(page) helper which always sends page and omits frame.","If building params manually, set either params.page OR params.frame, never both, and ensure at least one is present.","Add an assertion in your call site: assert((page ? 1 : 0) + (frame ? 1 : 0) === 1)."],"exampleFix":"// before: ambiguous or empty target\nawait connection.send('browserContext', 'newCDPSession', { context }); // no page/frame\n\n// after: exactly one target handle\nawait context.newCDPSession(page);","handlingStrategy":"validation","validationCode":"// Ensure exactly one of page/frame is supplied.\nfunction validateCdpTarget(params: { page?: any; frame?: any }) {\n  const count = (params.page ? 1 : 0) + (params.frame ? 1 : 0);\n  if (count !== 1) throw new Error('newCDPSession needs exactly one of page or frame');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the typed client helper context.newCDPSession(page) instead of building params by hand.","If you must build params, assert exactly one target field is set before sending.","Avoid conditional code that can populate both page and frame simultaneously."],"tags":["cdp","validation","protocol","browser-type"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}