{"record":{"id":"afc0d92be7fec803","repo":"microsoft/playwright","slug":"serializedargs-is-not-an-array-this-can-happen-wh","errorCode":null,"errorMessage":"serializedArgs is not an array. This can happen when Array.prototype.toJSON is defined incorrectly","messagePattern":"serializedArgs is not an array\\. This can happen when Array\\.prototype\\.toJSON is defined incorrectly","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/page.ts","lineNumber":1086,"sourceCode":"  forClient?: unknown;\n\n  constructor(parent: BrowserContext | Page, name: string, playwrightFunction: frames.FunctionWithSource, noGlobal?: boolean) {\n    super(parent);\n    this.name = name;\n    this.playwrightFunction = playwrightFunction;\n    this.initScript = new InitScript(parent, `globalThis['${kBindingsControllerProperty}'].addBinding(${JSON.stringify(name)}, ${!!noGlobal})`);\n    this.cleanupScript = `globalThis['${kBindingsControllerProperty}'].removeBinding(${JSON.stringify(name)})`;\n  }\n\n  static async dispatch(page: Page, payload: string, context: dom.FrameExecutionContext) {\n    const { name, seq, serializedArgs } = JSON.parse(payload) as BindingPayload;\n    try {\n      assert(context.world);\n      const binding = page.getBinding(name);\n      if (!binding)\n        throw new Error(`Function \"${name}\" is not exposed`);\n      if (!Array.isArray(serializedArgs))\n        throw new Error(`serializedArgs is not an array. This can happen when Array.prototype.toJSON is defined incorrectly`);\n      const args = serializedArgs.map(a => parseEvaluationResultValue(a));\n      const result = await binding.playwrightFunction({ frame: context.frame, page, context: page.browserContext }, ...args);\n      context.evaluateExpressionHandle(`arg => globalThis['${kBindingsControllerProperty}'].deliverBindingResult(arg)`, { isFunction: true }, { name, seq, result }).catch(e => debugLogger.log('error', e));\n    } catch (error) {\n      context.evaluateExpressionHandle(`arg => globalThis['${kBindingsControllerProperty}'].deliverBindingResult(arg)`, { isFunction: true }, { name, seq, error }).catch(e => debugLogger.log('error', e));\n    }\n  }\n\n  override async dispose(): Promise<void> {\n    await this.parent.removeExposedBinding(this);\n  }\n}\n\nexport class InitScript extends DisposableObject {\n  readonly source: string;\n\n  constructor(owner: BrowserContext | Page, source: string) {\n    super(owner);","sourceCodeStart":1068,"sourceCodeEnd":1104,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/page.ts#L1068-L1104","documentation":"Thrown by PageBinding.dispatch when the binding payload's serializedArgs field is not an Array. Playwright serializes binding arguments through JSON; if page-side code overrode Array.prototype.toJSON (or similar) the serialized value is no longer a JSON array and cannot be spread into the callback, so dispatch aborts with a hint pointing at the likely culprit.","triggerScenarios":"The page under test (or a third-party script it loads) defines Array.prototype.toJSON, mutating how arrays serialize; a loaded library patches Array.prototype before the binding call; the payload is constructed/forwarded by custom code that does not pass a real array.","commonSituations":"Legacy libraries that polyfill toJSON on Array for older IE compatibility; test pages that include legacy prototype extensions; monkeypatched globals in the page environment.","solutions":["Find and remove the Array.prototype.toJSON override (or any Array prototype mutation) in the page or its loaded scripts.","If a library requires the override, scope it so it does not run during binding serialization, or delete Array.prototype.toJSON before invoking the exposed function.","Pass primitive/plain-object arguments to exposed functions and avoid relying on custom toJSON on collections."],"exampleFix":"// page-side culprit\nArray.prototype.toJSON = function() { return [...this]; }; // breaks serialization\n// fix\nawait page.evaluate(() => { delete (Array.prototype as any).toJSON; });\nawait page.evaluate(() => window.cb(1, 2, 3));","handlingStrategy":"validation","validationCode":"// Strip known prototype pollution before exercising bindings\nawait page.addInitScript(() => {\n  delete (Array.prototype as any).toJSON;\n  delete (Object.prototype as any).toJSON;\n});","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Audit page-loaded scripts for Array.prototype/Object.prototype mutations.","Remove legacy toJSON polyfills that target obsolete browsers.","Use addInitScript to neutralize prototype overrides before app code runs."],"tags":["bindings","json-serialization","prototype-pollution","page-context"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}