Version
1.62.1
Steps to reproduce
browserContext.storageState({ indexedDB: true }) leaves an open IndexedDB connection in the page it reads from. That connection then blocks any later attempt to delete or recreate the database on that origin — including the one browserContext.setStorageState() performs internally. The result is a promise that never settles and never times out.
Two independent symptoms follow from the same leaked connection:
- After
storageState({ indexedDB: true }), indexedDB.deleteDatabase() in the page fires onblocked instead of onsuccess.
setStorageState() with a state containing IndexedDB hangs forever while a page of the context is open on that origin. It is not affected by context.setDefaultTimeout().
Reproduction (Chromium, macOS; any origin works — the snippet uses example.com):
const { chromium } = require('playwright');
const SEED = async () => {
const req = indexedDB.open('rfdb', 1);
req.onupgradeneeded = () => req.result.createObjectStore('kv');
const db = await new Promise((res, rej) => {
req.onsuccess = () => res(req.result);
req.onerror = () => rej(req.error);
});
await new Promise((res, rej) => {
const tx = db.transaction('kv', 'readwrite');
tx.objectStore('kv').put('token-abc', 'auth');
tx.oncomplete = () => res();
tx.onerror = () => rej(tx.error);
});
db.close();
};
const DELETE = async () => {
await new Promise((res, rej) => {
const req = indexedDB.deleteDatabase('rfdb');
req.onsuccess = () => res();
req.onerror = () => rej(req.error);
req.onblocked = () => rej(new Error('blocked'));
});
};
(async () => {
const browser = await chromium.launch();
// Symptom 1: storageState({indexedDB}) leaves a connection open.
for (const withSave of [false, true]) {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com/');
await page.evaluate(SEED);
if (withSave) await context.storageState({ indexedDB: true });
let result = 'ok';
try {
await page.evaluate(DELETE);
} catch {
result = 'BLOCKED';
}
console.log(`storageState({indexedDB}) called first = ${withSave} -> deleteDatabase ${result}`);
await context.close();
}
// Symptom 2: setStorageState() never settles, and ignores the context timeout.
const context = await browser.newContext();
context.setDefaultTimeout(3000);
const page = await context.newPage();
await page.goto('https://example.com/');
await page.evaluate(SEED);
const state = await context.storageState({ indexedDB: true });
const outcome = await Promise.race([
context.setStorageState(state).then(() => 'resolved', (e) => 'rejected: ' + e.message),
new Promise((res) => setTimeout(() => res('still pending after 20s'), 20000)),
]);
console.log(`setStorageState -> ${outcome}`);
process.exit(0);
})();
Expected behavior
storageState({ indexedDB: true }) closes the IndexedDB connections it opens, so that the page it read from is left exactly as it was found. setStorageState() restores the state regardless of whether pages of the context are open on the affected origin, and — if it genuinely cannot proceed — rejects within the context timeout rather than hanging.
Actual behavior
storageState({indexedDB}) called first = false -> deleteDatabase ok
storageState({indexedDB}) called first = true -> deleteDatabase BLOCKED
setStorageState -> still pending after 20s
The promise returned by setStorageState() never settles. context.setDefaultTimeout(3000) has no effect on it.
Additional context
Workarounds
Anything that drops the page's IndexedDB connections before setStorageState() makes it resolve, and the data is then restored correctly:
Between storageState() and setStorageState() |
Result |
| nothing |
hangs |
page.reload() |
resolves, value restored |
page.goto('about:blank') |
resolves, value restored |
page.close() |
resolves, value restored |
| restore into a different, freshly created context |
resolves, value restored |
Environment
- Playwright: 1.62.1
- Browser: Chromium (bundled)
- OS: macOS 15 (Darwin 25.5.0), arm64
- Node.js: v22.20.0
Environment
System:
OS: macOS 26.5.1
CPU: (12) arm64 Apple M2 Max
Memory: 71.11 MB / 32.00 GB
Binaries:
Node: 22.20.0 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/node
Yarn: 1.22.22 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/yarn
npm: 11.6.2 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/npm
pnpm: 10.30.3 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/pnpm
IDEs:
VSCode: 1.132.0 - /usr/local/bin/code
Claude Code: 2.1.233 - /Users/XXX/.local/bin/claude
Codex: 0.147.0 - /Users/XXX/.local/bin/codex
Languages:
Bash: 3.2.57 - /bin/bash
npmPackages:
playwright: ^1.62.1 => 1.62.1
Version
1.62.1
Steps to reproduce
browserContext.storageState({ indexedDB: true })leaves an open IndexedDB connection in the page it reads from. That connection then blocks any later attempt to delete or recreate the database on that origin — including the onebrowserContext.setStorageState()performs internally. The result is a promise that never settles and never times out.Two independent symptoms follow from the same leaked connection:
storageState({ indexedDB: true }),indexedDB.deleteDatabase()in the page firesonblockedinstead ofonsuccess.setStorageState()with a state containing IndexedDB hangs forever while a page of the context is open on that origin. It is not affected bycontext.setDefaultTimeout().Reproduction (Chromium, macOS; any origin works — the snippet uses
example.com):Expected behavior
storageState({ indexedDB: true })closes the IndexedDB connections it opens, so that the page it read from is left exactly as it was found.setStorageState()restores the state regardless of whether pages of the context are open on the affected origin, and — if it genuinely cannot proceed — rejects within the context timeout rather than hanging.Actual behavior
The promise returned by
setStorageState()never settles.context.setDefaultTimeout(3000)has no effect on it.Additional context
Workarounds
Anything that drops the page's IndexedDB connections before
setStorageState()makes it resolve, and the data is then restored correctly:storageState()andsetStorageState()page.reload()page.goto('about:blank')page.close()Environment
Environment
System: OS: macOS 26.5.1 CPU: (12) arm64 Apple M2 Max Memory: 71.11 MB / 32.00 GB Binaries: Node: 22.20.0 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/node Yarn: 1.22.22 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/yarn npm: 11.6.2 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/npm pnpm: 10.30.3 - /Users/XXX/.nvm/versions/node/v22.20.0/bin/pnpm IDEs: VSCode: 1.132.0 - /usr/local/bin/code Claude Code: 2.1.233 - /Users/XXX/.local/bin/claude Codex: 0.147.0 - /Users/XXX/.local/bin/codex Languages: Bash: 3.2.57 - /bin/bash npmPackages: playwright: ^1.62.1 => 1.62.1