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

  1. Guard with frame.parentFrame() before calling frame.frameElement(); skip or no-op for the main frame.
  2. Check frame.isDetached() and short-circuit before resolving the owner element.
  3. 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

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


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/6a0abe55c66507ca. Report an issue: GitHub.