{"record":{"id":"3a5d486289916e6f","repo":"puppeteer/puppeteer","slug":"trying-to-evaluate-jshandle-from-different-global","errorCode":null,"errorMessage":"Trying to evaluate JSHandle from different global types. Usually this means you're using a handle from a worker in a page or vice versa.","messagePattern":"Trying to evaluate JSHandle from different global types\\. Usually this means you're using a handle from a worker in a page or vice versa\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/puppeteer-core/src/bidi/Realm.ts","lineNumber":246,"sourceCode":"    }\n    return BidiJSHandle.from(result, this);\n  }\n\n  async serializeAsync(arg: unknown): Promise<Bidi.Script.LocalValue> {\n    if (arg instanceof LazyArg) {\n      arg = await arg.get(this);\n    }\n    return this.serialize(arg);\n  }\n\n  serialize(arg: unknown): Bidi.Script.LocalValue {\n    if (arg instanceof BidiJSHandle || arg instanceof BidiElementHandle) {\n      if (arg.realm !== this) {\n        if (\n          !(arg.realm instanceof BidiFrameRealm) ||\n          !(this instanceof BidiFrameRealm)\n        ) {\n          throw new Error(\n            \"Trying to evaluate JSHandle from different global types. Usually this means you're using a handle from a worker in a page or vice versa.\",\n          );\n        }\n        if (arg.realm.environment !== this.environment) {\n          throw new Error(\n            \"Trying to evaluate JSHandle from different frames. Usually this means you're using a handle from a page on a different page.\",\n          );\n        }\n      }\n      if (arg.disposed) {\n        throw new Error('JSHandle is disposed!');\n      }\n      return arg.remoteValue() as Bidi.Script.RemoteReference;\n    }\n\n    return BidiSerializer.serialize(arg);\n  }\n","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/puppeteer/puppeteer/blob/d484e21c17f6023826fefdcdeeb553e04a7aaed8/packages/puppeteer-core/src/bidi/Realm.ts#L228-L264","documentation":"Thrown by Realm.serialize() when a JSHandle/ElementHandle being passed as an evaluation argument belongs to a realm of a different global type than the target realm — specifically when one is a BidiFrameRealm (window) and the other is a BidiWorkerRealm (worker), or one is frame and the other worker. Cross-global-type handle passing is impossible because workers and pages have disjoint object graphs.","triggerScenarios":"Passing a handle obtained from `page.evaluateHandle(...)` (frame realm) into `worker.evaluate(...)` or vice versa; passing an ElementHandle from the page into a WebWorker's evaluate; calling `worker.evaluate(fn, pageHandle)`.","commonSituations":"Sharing handles across page and worker in test harnesses; refactoring that moved an evaluateHandle call from page to worker without re-acquiring the handle; assuming workers can see page DOM directly.","solutions":["Re-acquire the handle inside the correct realm: serialize the value to a primitive in the source realm and pass that, or re-query the DOM in the page.","For DOM access from a worker, message-pass node data via postMessage rather than passing an ElementHandle.","Confirm both handles share the same realm type before combining them in one evaluate.","Use `worker.evaluateHandle(...)` to create handles native to the worker realm."],"exampleFix":"// before\nconst handle = await page.evaluateHandle(() => window);\nawait worker.evaluate(h => h.location, handle); // throws: different global types\n\n// after\nawait worker.evaluate(() => self.location);","handlingStrategy":"type-guard","validationCode":"// Compare realm kinds before cross-passing handles (uses public frame mainRealm).\nconst sameRealmKind = (a: any, b: any) =>\n  !!a && !!b && a?.constructor?.name === b?.constructor?.name;","typeGuard":"// Heuristic: element/JS handles from workers come via WebWorker; page handles via Page.\nconst isWorkerHandle = (h: any): boolean =>\n  !!h?.realm && /Worker/.test(h.realm?.constructor?.name ?? '');","tryCatchPattern":"try {\n  await worker.evaluate(fn, pageHandle);\n} catch (e) {\n  if (/different global types/.test(String(e?.message))) {\n    // re-acquire or pass primitives instead\n  } else { throw e; }\n}","preventionTips":["Never pass page handles into worker evaluates; pass primitives.","Acquire handles in the same realm that will consume them.","Use postMessage patterns to share data between page and worker."],"tags":["realm","jshandle","worker","bidi","cross-context","usage-error"],"backgroundTag":null,"analyzedSha":"d484e21c17f6023826fefdcdeeb553e04a7aaed8","analyzedAt":"2026-08-12T06:33:19.665Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}