{"record":{"id":"8e895e554b051825","repo":"microsoft/playwright","slug":"cannot-set-cookies-without-an-open-page","errorCode":null,"errorMessage":"Cannot set cookies without an open page","messagePattern":"Cannot set cookies without an open page","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/webkit/webview/wvBrowser.ts","lineNumber":337,"sourceCode":"    return network.filterCookies(cookies.map(c => {\n      const copy: channels.NetworkCookie = {\n        name: c.name,\n        value: c.value,\n        domain: c.domain,\n        path: c.path,\n        expires: c.session ? -1 : c.expires / 1000,\n        httpOnly: c.httpOnly,\n        secure: c.secure,\n        sameSite: c.sameSite,\n      };\n      return copy;\n    }), urls);\n  }\n\n  async addCookies(cookies: channels.SetNetworkCookie[]) {\n    const page = this._cookiePage();\n    if (!page)\n      throw new Error('Cannot set cookies without an open page');\n    const protocolCookies = network.rewriteCookies(cookies).map(c => {\n      const session = c.expires === undefined || c.expires === -1;\n      const cookie: Protocol.Page.Cookie = {\n        name: c.name,\n        value: c.value,\n        domain: c.domain!,\n        path: c.path!,\n        expires: session ? 0 : c.expires! * 1000,\n        session,\n        httpOnly: !!c.httpOnly,\n        secure: !!c.secure,\n        sameSite: c.sameSite ?? 'Lax',\n      };\n      return cookie;\n    });\n    await page.setCookies(protocolCookies);\n  }\n","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/webkit/webview/wvBrowser.ts#L319-L355","documentation":"On the iOS Safari webview backend, cookie operations are scoped to an open page (the WKWebView only exposes document.cookie for the current page's domain). addCookies needs that page to inject cookies via the page protocol; with zero pages attached there is nowhere to write, so it throws. doGetCookies returns [] in the same situation, but addCookies cannot silently no-op.","triggerScenarios":"Calling context.addCookies([...]) on a webview context after all tabs/pages have closed (or before any page is attached); calling addCookies right after connect when the single tab detached.","commonSituations":"A test that sets up cookies before navigating, against an iOS Safari session where the initial tab disappeared; teardown ordering that closes the page before cookie setup of the next test.","solutions":["Ensure at least one page is open (context.pages().length > 0) before calling addCookies on a webview context.","Navigate the existing page to the target domain first, then addCookies, then continue.","If the page closed, reconnect or have the user reopen Safari before setting cookies."],"exampleFix":"// before\nawait context.addCookies([{ name: 'sid', value: '1', domain: 'example.com', path: '/' }]);\n// throws if no page attached\n\n// after\nconst page = context.pages()[0];\nif (page) {\n  await page.goto('https://example.com');\n  await context.addCookies([{ name: 'sid', value: '1', domain: 'example.com', path: '/' }]);\n}","handlingStrategy":"validation","validationCode":"function assertPageForCookies(context) {\n  if (!context.pages().length) throw new Error('Open a page before adding cookies on a webview context.');\n}\nassertPageForCookies(context);\nawait context.addCookies(cookies);","typeGuard":null,"tryCatchPattern":"try { await context.addCookies(cookies); }\ncatch (e) {\n  if (/without an open page/i.test(String(e.message))) {\n    await context.pages()[0]?.goto(targetUrl);\n    await context.addCookies(cookies);\n  } else throw e;\n}","preventionTips":["Ensure context.pages().length > 0 before addCookies on webview.","Navigate the existing page to the target domain before setting cookies.","Don't close the page before setting up cookies for the next test."],"tags":["webview","ios","cookies","capability"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}