microsoft/playwright · error · Error
Resulting promise was garbage collected.
Error message
Resulting promise was garbage collected.
What it means
Rewritten in rewriteError() (crExecutionContext.ts:108) when CDP reports 'Promise was collected'. The promise returned by an evaluated async function was garbage-collected in the page before it settled, so its resolution cannot be delivered.
Source
Thrown at packages/playwright-core/src/server/chromium/crExecutionContext.ts:108
async releaseHandle(handle: js.JSHandle): Promise<void> {
if (!handle._objectId)
return;
await releaseObject(this._client, handle._objectId);
}
shouldPrependErrorPrefix(): boolean {
return false;
}
}
function rewriteError(error: Error): Protocol.Runtime.evaluateReturnValue {
if (error.message.includes('Object reference chain is too long') || error.message.includes('CBOR: stack limit exceeded'))
throw new Error('Cannot serialize result: object reference chain is too long.');
if (error.message.includes('Object couldn\'t be returned by value'))
return { result: { type: 'undefined' } };
if (error.message.includes('Promise was collected'))
throw new Error('Resulting promise was garbage collected.');
if (error instanceof TypeError && error.message.startsWith('Converting circular structure to JSON'))
rewriteErrorMessage(error, error.message + ' Are you passing a nested JSHandle?');
if (!js.isJavaScriptErrorInEvaluate(error) && !isSessionClosedError(error))
throw new Error('Execution context was destroyed, most likely because of a navigation.');
throw error;
}
function potentiallyUnserializableValue(remoteObject: Protocol.Runtime.RemoteObject): any {
const value = remoteObject.value;
const unserializableValue = remoteObject.unserializableValue;
return unserializableValue ? js.parseUnserializableValue(unserializableValue) : value;
}
function renderPreview(object: Protocol.Runtime.RemoteObject): string | undefined {
if (object.type === 'undefined')
return 'undefined';
if ('value' in object)View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Store the promise in a page-scope variable (e.g. window.__pending) so it stays reachable, then return it.
- Use page.waitForFunction with a polling predicate instead of returning a long-lived promise.
- Run the async work to completion inside evaluate and return only the final primitive.
Example fix
// before
const ok = await page.evaluate(() => fetch('/x').then(r => r.ok));
// after
const ok = await page.evaluate(async () => {
const p = fetch('/x').then(r => r.ok);
window.__pending = p;
return await p;
}); Defensive patterns
Strategy: validation
Validate before calling
// Keep the promise reachable in page scope until it settles.
const ok = await page.evaluate(async () => {
const p = fetch('/x').then(r => r.ok);
(window as any).__pending = (window as any).__pending || [];
(window as any).__pending.push(p);
return await p;
}); Prevention
- Avoid returning fire-and-forget promises from evaluate.
- Use page.waitForFunction for conditions that take time to become true.
- If you must return a promise, retain it on a page-level variable.
When it happens
Trigger: page.evaluate(() => someAsyncWork()) where the work loses its only reference; returning a promise that the page lets go of (fire-and-forget); awaiting on a promise stored in a weak map.
Common situations: Returning fetch().then() chains without retaining them; awaiting promises that the SPA drops after re-render; long-running tasks that lose their root reference.
Related errors
- Cannot serialize result: object reference chain is too long.
- Execution context was destroyed, most likely because of a na
- PDF creation is only working with Chromium
- Cannot serialize result: object reference chain is too long.
- Method not implemented.
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/b23e31d12bb86d69.
Report an issue: GitHub.