microsoft/playwright · error · Error
Frame has been detached.
Error message
Frame has been detached.
What it means
Thrown by getFrameElement() in the webview backend when frame.parentFrame() returns null. A Frame with no parent is either a top-level main frame or a frame whose parent has already been detached/destroyed. Since getFrameElement's job is to find the <iframe>/<frame> element in the parent document, a missing parent makes the operation meaningless.
Source
Thrown at packages/playwright-core/src/server/webkit/webview/wvPage.ts:1000
}
return path;
}
private async _childFrameAndDispose(progress: Progress, iframe: dom.ElementHandle): Promise<frames.Frame | null> {
try {
return await progress.race(this.getContentFrame(iframe));
} finally {
iframe.dispose();
}
}
async resetForReuse(progress: Progress): Promise<void> {
}
async getFrameElement(frame: frames.Frame): Promise<dom.ElementHandle> {
const parent = frame.parentFrame();
if (!parent)
throw new Error('Frame has been detached.');
// Requesting the frame's own document streams its ancestor path, which
// includes the owner element (and its siblings). Pick the one whose
// contentDocument is this frame, then resolve it in the parent's context.
const documentHandle = await (await frame.mainContext()).evaluateHandle(() => document);
let ownerNodeId: number | undefined;
try {
if (documentHandle._objectId) {
const { nodesById } = await this._requestNodeViaDOM(documentHandle._objectId);
for (const node of nodesById.values()) {
if (node.contentDocument?.frameId === frame._id) {
ownerNodeId = node.nodeId;
break;
}
}
}
} finally {
documentHandle.dispose();
}View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Guard with frame.parentFrame() before calling frame.frameElement(); skip or no-op for the main frame.
- Check frame.isDetached() and short-circuit before resolving the owner element.
- Refresh the Frame reference from page.frames() after navigation/iframe removal and retry on the fresh instance.
Example fix
// before const el = await frame.frameElement(); // after if (frame.isDetached() || !frame.parentFrame()) return null; const el = await frame.frameElement();
Defensive patterns
Strategy: validation
Validate before calling
function canGetFrameElement(frame) {
return !!frame.parentFrame() && !frame.isDetached();
}
// usage
if (canGetFrameElement(frame)) await frame.frameElement(); Type guard
function hasParentFrame(frame: any): frame is import('playwright-core').Frame {
return !!frame && typeof frame.parentFrame === 'function' && !!frame.parentFrame();
} Try / catch
try { return await frame.frameElement(); }
catch (e) {
if ((e as Error).message === 'Frame has been detached.') return null;
throw e;
} Prevention
- Never call frameElement() on page.mainFrame().
- Re-acquire Frame references from page.frames() after navigation/iframe removal.
When it happens
Trigger: Calling frame.frameElement() (or any internal code that resolves a frame's owner element) on the main frame, or on an iframe whose parent frame was removed from the DOM before the call resolves. Also reachable during cross-frame quad/pointer math that walks frame trees in wvPage.
Common situations: Holding a stale Frame reference after the iframe element was removed. Calling frameElement() on page.mainFrame(). Race between iframe detach and a snapshot/locator operation running on the webview transport.
Related errors
- Frame has been detached.
- Frame has been detached.
- Frame was detached
- Unknown target: ${targetId}
- Unable to adopt element handle from a different document
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/6a0abe55c66507ca.
Report an issue: GitHub.