{"record":{"id":"860b593625465e00","repo":"denoland/deno","slug":"datacloneerror","errorCode":"DataCloneError","errorMessage":"Cannot clone object of unsupported type.","messagePattern":"Cannot clone object of unsupported type\\.","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/worker_threads.ts","lineNumber":792,"sourceCode":"      }\n    }\n  };\n\n  postMessage(message, transferOrOptions = { __proto__: null }) {\n    const prefix = \"Failed to execute 'postMessage' on 'MessagePort'\";\n    webidl.requiredArguments(arguments.length, 1, prefix);\n    if (this.#status !== \"RUNNING\") return;\n    // Fast path: no transferables\n    if (\n      transferOrOptions === undefined ||\n      transferOrOptions === null ||\n      (arguments.length <= 1)\n    ) {\n      // Reject non-serializable values (e.g. URL) and per-instance\n      // markAsUncloneable values before V8's serializer silently turns them\n      // into `{}`, matching the web MessagePort path and Node's behavior.\n      if (isUncloneable(message)) {\n        throw new DOMException(\n          \"Cannot clone object of unsupported type.\",\n          \"DataCloneError\",\n        );\n      }\n      op_host_post_message_raw(\n        this.#id,\n        serializeMessageData(message),\n      );\n      return;\n    }\n    message = webidl.converters.any(message);\n    let options;\n    if (\n      webidl.type(transferOrOptions) === \"Object\" &&\n      transferOrOptions !== undefined &&\n      transferOrOptions[SymbolIterator] !== undefined\n    ) {\n      const transfer = webidl.converters[\"sequence<object>\"](","sourceCodeStart":774,"sourceCodeEnd":810,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/worker_threads.ts#L774-L810","documentation":"Worker.postMessage serializes with structured clone. On the no-transfer fast path the polyfill first checks an isUncloneable marker (honoring markAsUncloneable) so values the V8 serializer would silently flatten to {} — URL objects, marked instances — instead throw DOMException 'Cannot clone object of unsupported type.' with DataCloneError, matching the web MessagePort path and Node's behavior.","triggerScenarios":"worker.postMessage(new URL('https://x')) or posting an instance registered via markAsUncloneable(); functions and other inherently non-cloneable values hit the same rejection.","commonSituations":"Sharing parsed URL or class-instance objects between threads and expecting JSON-like behavior; libraries that mark handles uncloneable to prevent silent data loss; values that otherwise 'arrive as empty object'.","solutions":["Convert to clone-safe data first: url.href instead of the URL object, plain objects instead of class instances.","Add a toJSON()/toPlain() conversion on your classes, or explicitly JSON round-trip when the data allows it.","For shared mutable state use SharedArrayBuffer instead of posting objects.","Respect markAsUncloneable — if a class is marked, pass its fields, not the instance."],"exampleFix":"// before\nworker.postMessage({ endpoint: new URL('https://api.example.com/v1') });\n\n// after\nworker.postMessage({ endpoint: 'https://api.example.com/v1' }); // strings clone cleanly","handlingStrategy":"type-guard","validationCode":"function isCloneable(v: unknown, depth = 0): boolean {\n  if (v == null) return true;\n  const t = typeof v;\n  if (t !== 'object') return t !== 'function' && t !== 'symbol';\n  if (v instanceof URL) return false; // known uncloneable\n  if (v instanceof Date || v instanceof RegExp || v instanceof ArrayBuffer || v instanceof SharedArrayBuffer) return true;\n  if (depth > 8) return false;\n  const kids = Array.isArray(v) ? v : (v instanceof Map || v instanceof Set) ? [...v] : Object.values(v as object);\n  return kids.every((x) => isCloneable(x, depth + 1));\n}\n\nif (!isCloneable(msg)) throw new TypeError('message is not structured-clone safe');\nworker.postMessage(msg);","typeGuard":"Use isCloneable from validationCode as a deep guard: if (!isCloneable(msg)) msg = toPlainObject(msg);","tryCatchPattern":"try { worker.postMessage(msg); } catch (e) { if (e?.name === 'DataCloneError') { /* re-send as serialized primitives, e.g. JSON round-trip */ } else throw e; }","preventionTips":["Keep worker messages plain data: POJOs, arrays, primitives.","Convert URL objects and class instances at the boundary with one sanitizeMessage() helper.","Write a clone-safety unit test for every new message payload shape."],"tags":["worker-threads","postmessage","structured-clone","datacloneerror"],"backgroundTag":"structured-clone-failure","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}