{"record":{"id":"328a2cacc5b44ab1","repo":"microsoft/playwright","slug":"this-frame-does-not-have-a-separate-cdp-session-i","errorCode":null,"errorMessage":"This frame does not have a separate CDP session, it is a part of the parent frame's session","messagePattern":"This frame does not have a separate CDP session, it is a part of the parent frame's session","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/playwright-core/src/server/chromium/crBrowser.ts","lineNumber":606,"sourceCode":"    // cancellation (finished, cancelled, etc.) or the guid is invalid at all.\n    await this._browser._session.send('Browser.cancelDownload', {\n      guid: guid,\n      browserContextId: this._browserContextId,\n    });\n  }\n\n  serviceWorkers(): CRServiceWorker[] {\n    return Array.from(this._browser._serviceWorkers.values()).filter(serviceWorker => serviceWorker.browserContext === this);\n  }\n\n  async newCDPSession(page: Page | Frame): Promise<CDPSession> {\n    let targetId: string | null = null;\n    if (page instanceof Page) {\n      targetId = (page.delegate as CRPage)._targetId;\n    } else if (page instanceof Frame) {\n      const session = (page._page.delegate as CRPage)._sessions.get(page._id);\n      if (!session)\n        throw new Error(`This frame does not have a separate CDP session, it is a part of the parent frame's session`);\n      targetId = session._targetId;\n    } else {\n      throw new Error('page: expected Page or Frame');\n    }\n\n    const rootSession = await this._browser._clientRootSession();\n    return rootSession.attachToTarget(targetId);\n  }\n}\n\nexport function shouldProxyLoopback(bypass: string | undefined) {\n  if (process.env.PLAYWRIGHT_DISABLE_FORCED_CHROMIUM_PROXIED_LOOPBACK)\n    return false;\n  const hosts = (bypass || '').split(',').map(s => s.trim());\n  const shouldBypassSomeLoopback = ['localhost', '127.0.0.1', '::1', '[::]', '[::1]', '<loopback>', '<-loopback>'].some(host => hosts.includes(host));\n  return !shouldBypassSomeLoopback;\n}\n","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/chromium/crBrowser.ts#L588-L624","documentation":"Thrown in CRBrowserContext.newCDPSession when called with a Frame whose _id has no entry in the CRPage _sessions map. Out-of-process frames (OOPIFs) get their own CDP target/session; same-process frames share the parent page's session and therefore cannot yield a dedicated CDPSession.","triggerScenarios":"await context.newCDPSession(someFrame) where someFrame is a same-process iframe (not an OOPIF), so no separate CDP session was attached to it.","commonSituations":"Calling newCDPSession on a frame to run CDP commands, but the iframe is same-origin (same process) and the browser never created a separate target for it. Code that works for cross-origin iframes fails for same-origin ones.","solutions":["Call newCDPSession on the Page instead (frames in the same process share the page's session), then target the frame via its target/frame ID.","If you truly need a per-frame session, ensure the frame is out-of-process (cross-site/origin-isolated) — but this is browser-dependent.","Use Playwright's frame APIs (frame.evaluate, frame.locator) instead of raw CDP for same-process frames."],"exampleFix":"// before\nconst sess = await context.newCDPSession(sameOriginFrame);\n// after\nconst sess = await context.newCDPSession(sameOriginFrame._page);\n// or avoid CDP:\nawait sameOriginFrame.evaluate(() => { /* ... */ });","handlingStrategy":"type-guard","validationCode":"async function safeNewCDPSession(context: any, target: any) {\n  if (target && target._id) {\n    const page = target._page;\n    const hasSession = page && page.delegate && page.delegate._sessions && page.delegate._sessions.has(target._id);\n    if (!hasSession) return context.newCDPSession(page); // fall back to the page session\n  }\n  return context.newCDPSession(target);\n}","typeGuard":"function frameHasOwnCDPSession(frame: any): boolean {\n  const page = frame?._page;\n  return !!(page?.delegate?._sessions?.has(frame._id));\n}","tryCatchPattern":"try {\n  session = await context.newCDPSession(frame);\n} catch (e) {\n  if (/does not have a separate CDP session/.test(String(e.message))) {\n    session = await context.newCDPSession(frame._page);\n  } else throw e;\n}","preventionTips":["Prefer Playwright frame APIs over raw CDP for same-process iframes.","Only request a frame-level CDPSession for out-of-process (cross-site) frames.","Fall back to the page's CDPSession when a frame shares its parent's session."],"tags":["cdp","frames","chromium","session"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}