microsoft/playwright · error · Error
Frame has been detached.
Error message
Frame has been detached.
What it means
In `getFrameElement`, when a frame has no parent frame (`parentFrame()` is null), Playwright treats it as detached — the frame is no longer in the frame tree. This guard fires before attempting to locate the frame's element node.
Source
Thrown at packages/playwright-core/src/server/bidi/bidiPage.ts:717
}
}
async inputActionEpilogue(): Promise<void> {
}
async resetForReuse(progress: Progress): Promise<void> {
// See https://github.com/microsoft/playwright/issues/22432.
await this.rawMouse.move(progress, 0, 0, 'none', new Set(), new Set(), false);
}
async pdf(options: channels.PagePdfParams): Promise<Buffer> {
return this._pdf.generate(options);
}
async getFrameElement(frame: frames.Frame): Promise<dom.ElementHandle> {
const parent = frame.parentFrame();
if (!parent)
throw new Error('Frame has been detached.');
const node = await this._getFrameNode(frame);
if (!node?.sharedId)
throw new Error('Frame has been detached.');
const parentFrameExecutionContext = await parent.mainContext();
return await toBidiExecutionContext(parentFrameExecutionContext).remoteObjectForNodeId(parentFrameExecutionContext, { sharedId: node.sharedId });
}
async _getFrameNode(frame: frames.Frame): Promise<bidi.Script.NodeRemoteValue | undefined> {
const parent = frame.parentFrame();
if (!parent)
return undefined;
const result = await this._session.send('browsingContext.locateNodes', {
context: parent._id,
locator: { type: 'context', value: { context: frame._id } },
});
const node = result.nodes[0];
return node;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Re-acquire the frame via `page.frame()` / `page.frames()` before calling frameElement()
- Check `frame.isDetached()` before use
- Don't cache Frame objects across navigations
Example fix
// before
const el = await staleFrame.frameElement();
// after
if (frame.isDetached()) throw new Error('frame gone');
const el = await frame.frameElement(); Defensive patterns
Strategy: validation
Validate before calling
function assertFrameAttached(frame: Frame): void {
if (frame.isDetached()) throw new Error('Frame is detached; re-acquire via page.frame().');
if (!frame.parentFrame()) throw new Error('Frame has no parent; cannot resolve frame element.');
}
assertFrameAttached(frame);
const el = await frame.frameElement(); Type guard
function isLiveFrame(frame: Frame): boolean {
return !frame.isDetached() && !!frame.parentFrame();
} Prevention
- Check `frame.isDetached()` before operating on a Frame
- Re-acquire frames via `page.frame()` / `page.frames()` rather than caching
- Avoid holding Frame references across navigations
When it happens
Trigger: Calling `frame.frameElement()` (or equivalent) on a frame whose parent reference is gone — the iframe was removed from the DOM or the page navigated away.
Common situations: Holding a stale `Frame` object after its iframe was removed; calling frameElement() after navigation destroyed the frame; detached-frame race during teardown.
Related errors
- Unable to adopt element handle from a different document
- Frame was detached
- Frame has been detached.
- Frame has been detached.
- "${part.body}" is only allowed as the first selector token,
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/5d27d599c3a37586.
Report an issue: GitHub.