{"record":{"id":"e629cb04079adc8f","repo":"microsoft/playwright","slug":"cannot-serialize-result-object-reference-chain-is","errorCode":null,"errorMessage":"Cannot serialize result: object reference chain is too long.","messagePattern":"Cannot serialize result: object reference chain is too long\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/bidi/bidiExecutionContext.ts","lineNumber":199,"sourceCode":"      target: this._target,\n      arguments: args,\n      // \"Root\" is necessary for the handle to be returned.\n      resultOwnership: createHandle ? bidi.Script.ResultOwnership.Root : bidi.Script.ResultOwnership.None,\n      serializationOptions: { maxObjectDepth: 0, maxDomDepth: 0 },\n      awaitPromise,\n      userActivation: true,\n    });\n    if (response.type === 'exception')\n      throw new js.JavaScriptErrorInEvaluate(response.exceptionDetails.text);\n    if (response.type === 'success')\n      return response.result;\n    throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response));\n  }\n}\n\nfunction rewriteError(error: Error): never {\n  if (error.message.includes('too much recursion') || error.message.includes('stack limit exceeded'))\n    throw new Error('Cannot serialize result: object reference chain is too long.');\n  throw error;\n}\n\nfunction renderPreview(remoteObject: bidi.Script.RemoteValue, nested = false): string {\n  switch (remoteObject.type) {\n    case 'undefined':\n    case 'null':\n      return remoteObject.type;\n    case 'number':\n    case 'boolean':\n    case 'string':\n      return String(remoteObject.value);\n    case 'bigint':\n      return `${remoteObject.value}n`;\n    case 'date':\n      return String(new Date(remoteObject.value));\n    case 'regexp':\n      return String(new RegExp(remoteObject.value.pattern, remoteObject.value.flags));","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts#L181-L217","documentation":"During BiDi serialization of an evaluation result, the browser reports a recursion/stack error when the returned value has a self-referential or extremely deep object graph. Playwright's `rewriteError` catches the raw 'too much recursion'/'stack limit exceeded' and rewrites it to this clearer message.","triggerScenarios":"`page.evaluate()` / `page.evaluateHandle()` returning a deeply nested or circular value (e.g. `() => window`, `() => document`, a DOM node with back-references) while running Firefox over BiDi. The BiDi serializer walks the graph and blows the stack.","commonSituations":"Returning `window` or large DOM subtrees from evaluate in BiDi mode; migrating from CDP to BiDi and hitting BiDi's stricter serialization depth; dumping live objects for debugging.","solutions":["Return only the scalar fields you need, not the live object graph","Serialize manually inside the page: `page.evaluate(() => JSON.stringify(obj))` then parse client-side","Flatten relevant properties into a plain object before returning","If you need a handle, use `evaluateHandle` and access properties lazily via `getProperty`"],"exampleFix":"// before\nconst win = await page.evaluate(() => window);\n\n// after\nconst href = await page.evaluate(() => window.location.href);\n// or\nconst json = await page.evaluate(() => JSON.stringify({ l: location.href, t: document.title }));\nconst data = JSON.parse(json);","handlingStrategy":"try-catch","validationCode":"// Keep evaluate returns shallow and acyclic by shape; validate before sending.\nfunction shallowSerialize(v: unknown): unknown {\n  if (v === null || typeof v !== 'object') return v;\n  const out: Record<string, unknown> = {};\n  for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n    if (val !== null && typeof val === 'object') out[k] = '[object]';\n    else out[k] = val;\n  }\n  return out;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const r = await page.evaluate(() => returningGraph);\n} catch (e) {\n  if (e instanceof Error && /reference chain is too long/.test(e.message)) {\n    // fall back to JSON stringified payload\n    const s = await page.evaluate(() => JSON.stringify(returningGraph));\n    return JSON.parse(s);\n  }\n  throw e;\n}","preventionTips":["Never return live DOM/window objects from evaluate; return primitives or flat data","JSON.stringify inside the page when you must return large structures","Use evaluateHandle + lazy getProperty for deep object access"],"tags":["bidi","firefox","evaluate","serialization"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}