microsoft/playwright · error · Error
Frame has been detached.
Error message
Frame has been detached.
What it means
getFrameElement() throws when frame.parentFrame() is null — the frame is the main frame or has no living parent. Without a parent document there is no owner <iframe> element to resolve, so the operation is undefined. Mirrors the wvPage variant but on the standard WKPage backend.
Source
Thrown at packages/playwright-core/src/server/webkit/wkPage.ts:1018
const result = await this._session.sendMayFail('DOM.resolveNode', {
objectId: handle._objectId,
executionContextId: (to.delegate as WKExecutionContext)._contextId
});
if (!result || result.object.subtype === 'null')
throw new Error(dom.kUnableToAdoptErrorMessage);
return createHandle(to, result.object) as dom.ElementHandle<T>;
}
async inputActionEpilogue(): Promise<void> {
}
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.');
const context = await parent.mainContext();
const result = await this._session.send('DOM.resolveNode', {
frameId: frame._id,
executionContextId: (context.delegate as WKExecutionContext)._contextId
});
if (!result || result.object.subtype === 'null')
throw new Error('Frame has been detached.');
return createHandle(context, result.object) as dom.ElementHandle;
}
private _maybeCancelCoopNavigationRequest(provisionalPage: WKProvisionalPage) {
const navigationRequest = provisionalPage.coopNavigationRequest();
for (const [requestId, request] of this._requestIdToRequest) {
if (request.request === navigationRequest) {
// Make sure the request completes if the provisional navigation is canceled.
this._onLoadingFailed(provisionalPage._session, {
requestId: requestId,
errorText: 'Provisiolal navigation canceled.',View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Guard with frame.parentFrame() and frame.isDetached() before calling frame.frameElement().
- Skip owner-element resolution for the main frame entirely.
- Re-acquire frames from page.frames() after navigation.
Example fix
// before const el = await frame.frameElement(); // after if (!frame.parentFrame() || frame.isDetached()) return null; const el = await frame.frameElement();
Defensive patterns
Strategy: validation
Validate before calling
function canGetOwner(frame) { return !!frame.parentFrame() && !frame.isDetached(); }
if (canGetOwner(frame)) await frame.frameElement(); Type guard
function hasLivingParent(frame: any): boolean { return !!frame?.parentFrame() && !frame.isDetached(); } Try / catch
try { return await frame.frameElement(); }
catch (e) { if (/Frame has been detached/.test(e.message)) return null; throw e; } Prevention
- Skip frameElement() on the main frame.
- Check isDetached() before resolving owner elements.
When it happens
Trigger: Calling frame.frameElement() (or internal getFrameElement) on page.mainFrame() or on a frame whose parent was detached. Any snapshot/locator path that resolves a frame's owner element.
Common situations: Calling frameElement() on the top frame. Holding a stale child Frame after the parent removed it. Race between detach and an owner-element resolution.
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/d3e0f6a840123157.
Report an issue: GitHub.