microsoft/playwright · error · Error

Cannot serialize result: object reference chain is too long.

Error message

Cannot serialize result: object reference chain is too long.

What it means

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.

Source

Thrown at packages/playwright-core/src/server/bidi/bidiExecutionContext.ts:199

      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 },
      awaitPromise,
      userActivation: true,
    });
    if (response.type === 'exception')
      throw new js.JavaScriptErrorInEvaluate(response.exceptionDetails.text);
    if (response.type === 'success')
      return response.result;
    throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response));
  }
}

function rewriteError(error: Error): never {
  if (error.message.includes('too much recursion') || error.message.includes('stack limit exceeded'))
    throw new Error('Cannot serialize result: object reference chain is too long.');
  throw error;
}

function renderPreview(remoteObject: bidi.Script.RemoteValue, nested = false): string {
  switch (remoteObject.type) {
    case 'undefined':
    case 'null':
      return remoteObject.type;
    case 'number':
    case 'boolean':
    case 'string':
      return String(remoteObject.value);
    case 'bigint':
      return `${remoteObject.value}n`;
    case 'date':
      return String(new Date(remoteObject.value));
    case 'regexp':
      return String(new RegExp(remoteObject.value.pattern, remoteObject.value.flags));

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Return only the scalar fields you need, not the live object graph
  2. Serialize manually inside the page: `page.evaluate(() => JSON.stringify(obj))` then parse client-side
  3. Flatten relevant properties into a plain object before returning
  4. If you need a handle, use `evaluateHandle` and access properties lazily via `getProperty`

Example fix

// before
const win = await page.evaluate(() => window);

// after
const href = await page.evaluate(() => window.location.href);
// or
const json = await page.evaluate(() => JSON.stringify({ l: location.href, t: document.title }));
const data = JSON.parse(json);
Defensive patterns

Strategy: try-catch

Validate before calling

// Keep evaluate returns shallow and acyclic by shape; validate before sending.
function shallowSerialize(v: unknown): unknown {
  if (v === null || typeof v !== 'object') return v;
  const out: Record<string, unknown> = {};
  for (const [k, val] of Object.entries(v as Record<string, unknown>)) {
    if (val !== null && typeof val === 'object') out[k] = '[object]';
    else out[k] = val;
  }
  return out;
}

Try / catch

try {
  const r = await page.evaluate(() => returningGraph);
} catch (e) {
  if (e instanceof Error && /reference chain is too long/.test(e.message)) {
    // fall back to JSON stringified payload
    const s = await page.evaluate(() => JSON.stringify(returningGraph));
    return JSON.parse(s);
  }
  throw e;
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


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