{"record":{"id":"a3f7ef3f4a82e01e","repo":"denoland/deno","slug":"datacloneerror-a3f7ef","errorCode":"DataCloneError","errorMessage":"Uncloneable value","messagePattern":"Uncloneable value","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"error","filePath":"ext/web/01_broadcast_channel.js","lineNumber":148,"sourceCode":"      // Create the rid immediately, otherwise there is a time window (and a\n      // race condition) where messages can get lost, because recv() is async.\n      rid = op_broadcast_subscribe();\n      recv();\n    }\n  }\n\n  postMessage(message) {\n    webidl.assertBranded(this, BroadcastChannelPrototype);\n\n    const prefix = \"Failed to execute 'postMessage' on 'BroadcastChannel'\";\n    webidl.requiredArguments(arguments.length, 1, prefix);\n\n    if (this[_closed]) {\n      throw new DOMException(\"Already closed\", \"InvalidStateError\");\n    }\n\n    if (typeof message === \"function\" || typeof message === \"symbol\") {\n      throw new DOMException(\"Uncloneable value\", \"DataCloneError\");\n    }\n\n    // Serialize the message, carrying any SharedArrayBuffer backing stores\n    // out-of-band (referenced by `sabId`) so the message can be deserialized by\n    // an arbitrary number of receivers. `sabId` is 0 when there are none.\n    const { 0: data, 1: sabId } = op_broadcast_serialize(message, null);\n\n    // Send to other listeners in this VM.\n    dispatch(this, this[_name], data, sabId);\n\n    // Send to listeners in other VMs. This must happen before returning from\n    // postMessage(), otherwise close() immediately after postMessage() can\n    // cancel the deferred send before other workers observe the message.\n    op_broadcast_send(rid, this[_name], data, sabId);\n\n    // In-VM dispatch deserialized eagerly and op_broadcast_send moved a clone\n    // of the backing stores into the cross-VM message, so the sender's stash\n    // entry is no longer needed.","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/01_broadcast_channel.js#L130-L166","documentation":"BroadcastChannel.postMessage (ext/web/01_broadcast_channel.js:148) rejects functions and symbols with DOMException DataCloneError before serialization, because structured clone (op_broadcast_serialize) can never clone them. Values nested deeper in the object graph are caught by the serializer itself, but the top-level typeof check short-circuits the common cases with this exact message.","triggerScenarios":"bc.postMessage(() => {}) or passing a handler reference instead of invoking it; bc.postMessage(Symbol('payload')); objects whose graph contains function or symbol values deeper inside.","commonSituations":"Trying to ship callbacks across tabs/workers as if BroadcastChannel were RPC; passing a method reference with missing parentheses; action objects keyed by symbol ids from stores or registries; sending class instances that carry symbol-valued fields.","solutions":["Send data only: strip functions and symbols before posting","Represent behavior as a serializable descriptor (e.g. { type: 'run', id, args }) and dispatch on the receiving side","Replace symbol keys with string keys for anything that crosses the channel"],"exampleFix":"// before\nbc.postMessage({ run: () => doWork(), id: Symbol('job') });\n\n// after\nbc.postMessage({ type: 'run', jobId: 'job-42', args: [1, 2] });","handlingStrategy":"type-guard","validationCode":"if (typeof message === \"function\" || typeof message === \"symbol\") {\n  throw new TypeError(\"BroadcastChannel payloads must be data\");\n}\nbc.postMessage(message);","typeGuard":"function isCloneableTopLevel(v: unknown): boolean {\n  return typeof v !== \"function\" && typeof v !== \"symbol\";\n}","tryCatchPattern":"try {\n  bc.postMessage(message);\n} catch (e) {\n  if (e instanceof DOMException && e.name === \"DataCloneError\") {\n    bc.postMessage(JSON.parse(JSON.stringify(message, (_k, val) =>\n      typeof val === \"function\" || typeof val === \"symbol\" ? undefined : val,\n    )));\n  } else {\n    throw e;\n  }\n}","preventionTips":["Send plain data (message objects with type + args), never callbacks","Check for missing parentheses when passing method results","Avoid symbols anywhere in payloads that cross structured-clone boundaries"],"tags":["broadcastchannel","structured-clone","serialization","messaging","dom-exception"],"backgroundTag":"dataclone-uncloneable-value","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}