microsoft/playwright · error · JavaScriptErrorInEvaluate
JSHandles can be evaluated only in the context they were cre
Error message
JSHandles can be evaluated only in the context they were created!
What it means
Thrown as a JavaScriptErrorInEvaluate by evaluateExpression() when a JSHandle being passed as an argument belongs to a different ExecutionContext than the one the evaluate is running in. Each frame (and each isolated world) has its own context; handles created in one cannot be referenced in another. The check compares handle._context against the target context.
Source
Thrown at packages/playwright-core/src/server/javascript.ts:280
args = args.map(arg => serializeAsCallArgument(arg, handle => {
if (handle instanceof JSHandle) {
if (!handle._objectId)
return { fallThrough: handle._value };
if (handle._disposed)
throw new JavaScriptErrorInEvaluate('JSHandle is disposed!');
const adopted = context.adoptIfNeeded(handle);
if (adopted === null)
return { h: pushHandle(Promise.resolve(handle)) };
toDispose.push(adopted);
return { h: pushHandle(adopted) };
}
return { fallThrough: handle };
}));
const utilityScriptObjects: JSHandle[] = [];
for (const handle of await Promise.all(handles)) {
if (handle._context !== context)
throw new JavaScriptErrorInEvaluate('JSHandles can be evaluated only in the context they were created!');
utilityScriptObjects.push(handle);
}
// See UtilityScript for arguments.
const utilityScriptValues = [options.isFunction, options.returnByValue, expression, args.length, ...args];
const script = `(utilityScript, ...args) => utilityScript.evaluate(...args)`;
try {
return await context._evaluateWithArguments(script, options.returnByValue || false, utilityScriptValues, utilityScriptObjects);
} finally {
toDispose.map(handlePromise => handlePromise.then(handle => handle.dispose()));
}
}
export function parseUnserializableValue(unserializableValue: string): any {
if (unserializableValue === 'NaN')
return NaN;
if (unserializableValue === 'Infinity')View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Create the JSHandle in the same frame/context where it will be used in evaluate.
- Re-query elements in the target frame instead of passing handles across frames.
- Extract serializable values (strings, numbers) from the handle before crossing context boundaries: const value = await handle.jsonValue().
- For cross-frame operations, use element handles' own evaluate methods which run in the element's context.
Example fix
// before
const handleFromFrameA = await frameA.evaluateHandle('document');
await frameB.evaluate(h => h.title, handleFromFrameA); // throws [335]
// after
const title = await frameA.evaluate(() => document.title);
// use the serializable value in frameB if needed Defensive patterns
Strategy: validation
Validate before calling
// Extract serializable value before crossing context boundaries const value = await handle.jsonValue(); // Now pass the plain value instead of the handle
Try / catch
try {
await frame.evaluate(fn, handle);
} catch (e) {
if (e.message.includes('only in the context they were created')) {
const json = await handle.jsonValue();
return frame.evaluate(fn, json);
}
throw e;
} Prevention
- Create handles in the same frame where they will be used.
- Extract serializable values before crossing frame/context boundaries.
- Use element.evaluateInUtility or element.evaluate for element-scoped evaluation.
When it happens
Trigger: Passing a JSHandle from Frame A's context to an evaluate on Frame B. Using a handle from the main world in an evaluate running in the utility world. Using a handle from a previous page in the current page's evaluate. Cross-origin iframe handles used in the parent frame's evaluate.
Common situations: Storing a handle from one frame and using it in another frame's evaluate. Handle created before a navigation that created a new context. Mixing handles from addInitScript-injected scripts with main-context evaluates. Using a handle from an isolated world (e.g., from a selector engine) in a regular evaluate.
Related errors
- JSHandle is disposed!
- Passed function is not well-serializable!
- Cannot serialize result: object reference chain is too long.
- JSHandle is not a DOM node handle
- Cannot serialize result: object reference chain is too long.
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/fc2361f7d2ecf7d5.
Report an issue: GitHub.