microsoft/playwright · error · Error
JSHandle is not a DOM node handle
Error message
JSHandle is not a DOM node handle
What it means
Thrown by the WebDriver BiDi execution context when an internal operation needs a remote object reference from a JSHandle, but the handle's `_objectId` is falsy. A primitive JSHandle (string, number, boolean, undefined, null) has no backing remote object in BiDi, so it cannot be used where a node/window handle reference is required.
Source
Thrown at packages/playwright-core/src/server/bidi/bidiExecutionContext.ts:167
}
async remoteObjectForNodeId(context: dom.FrameExecutionContext, nodeId: bidi.Script.SharedReference): Promise<dom.ElementHandle> {
const result = await this._remoteValueForReference(nodeId, true);
if (!('handle' in result))
throw new Error('Can\'t get remote object for nodeId');
return createHandle(context, result) as dom.ElementHandle;
}
async contentFrameIdForFrame(handle: dom.ElementHandle) {
const contentWindow = await this._rawCallFunction('e => e.contentWindow', [{ handle: handle._objectId }]);
if (contentWindow?.type === 'window')
return contentWindow.value.context;
return null;
}
async frameIdForWindowHandle(handle: js.JSHandle): Promise<string | null> {
if (!handle._objectId)
throw new Error('JSHandle is not a DOM node handle');
const contentWindow = await this._remoteValueForReference({ handle: handle._objectId });
if (contentWindow.type === 'window')
return contentWindow.value.context;
return null;
}
private async _remoteValueForReference(reference: bidi.Script.RemoteReference, createHandle?: boolean) {
return await this._rawCallFunction('e => e', [reference], createHandle);
}
private async _rawCallFunction(functionDeclaration: string, args: bidi.Script.LocalValue[], createHandle?: boolean, awaitPromise = true): Promise<bidi.Script.RemoteValue> {
const response = await this._session.send('script.callFunction', {
functionDeclaration,
target: this._target,
arguments: args,
// "Root" is necessary for the handle to be returned.
resultOwnership: createHandle ? bidi.Script.ResultOwnership.Root : bidi.Script.ResultOwnership.None,
serializationOptions: { maxObjectDepth: 0, maxDomDepth: 0 },View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Obtain handles from expressions that return objects/windows, e.g. `page.evaluateHandle(() => window)`, not primitives
- If you hit this through a public API, file a Playwright issue with a repro — it typically signals an internal invariant violation
- Avoid passing arbitrary `evaluateHandle` results into frame/element APIs; re-query the element with a Locator
Example fix
// before
const h = await page.evaluateHandle(() => 'foo');
// ... passed into frame logic
// after
const h = await page.evaluateHandle(() => window);
// or re-query the node directly
const loc = page.locator('iframe'); Defensive patterns
Strategy: try-catch
Validate before calling
// _objectId is internal; guard at the public boundary by ensuring // the handle comes from an object-returning expression. const h = await page.evaluateHandle(() => window); // Re-query nodes via Locators rather than reusing arbitrary handles.
Type guard
// No public _objectId; approximate by checking the handle is non-primitive.
function isObjectHandle(h: JSHandle): boolean {
// Primitives report these types; objects/nodes report 'object'/'function'/'node'.
const t = (h as any)._objectType ?? 'object';
return t === 'object' || t === 'function' || t === 'node';
} Try / catch
try {
// operation that needs a node/window handle
} catch (e) {
if (e instanceof Error && /not a DOM node handle/.test(e.message)) {
// re-acquire a valid handle or rethrow with context
}
throw e;
} Prevention
- Prefer Locators over manually managed ElementHandles/JSHandles
- Obtain handles from object/window-returning expressions, not primitives
- Treat this error as an internal-invariant violation and report it upstream
When it happens
Trigger: Internal call to `frameIdForWindowHandle(handle)` in bidiExecutionContext.ts:167 where `handle._objectId` is undefined. Reached when BiDi frame/window introspection is given a handle produced by `page.evaluateHandle(() => somePrimitive)` instead of an object/window.
Common situations: Rare for end users. Surfaces in Firefox-over-BiDi when a primitive-valued JSHandle leaks into frame-resolution logic, or when internal helpers are reused with handles of the wrong shape. Usually indicates a Playwright internal bug rather than a user mistake.
Related errors
- Cannot serialize result: object reference chain is too long.
- Method not implemented.
- Not implemented
- Unable to adopt element handle from a different document
- Firefox distribution '${name}' is not supported on ${process
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/825678860f713048.
Report an issue: GitHub.