denoland/deno · error · DOMException

DataCloneError

DataCloneError

Error message

e.message

What it means

structuredClone delegates to the native structured-clone serializer; when the value graph contains something the algorithm cannot handle (functions, symbols, platform objects without serialization support), the op throws a TypeError which is rewrapped as DOMException DataCloneError carrying the same message (ext/web/02_structured_clone.js:139-143). Only TypeErrors are converted — other exceptions propagate unchanged. This is the same DataCloneError family raised by postMessage on uncloneable data.

Source

Thrown at ext/web/02_structured_clone.js:141

      case "Float32Array":
        Constructor = Float32Array;
        break;
      case "Float64Array":
        Constructor = Float64Array;
        break;
    }
    return new Constructor(
      structuredClone(TypedArrayPrototypeGetBuffer(value)),
      TypedArrayPrototypeGetByteOffset(value),
      TypedArrayPrototypeGetLength(value),
    );
  }

  try {
    return core.structuredClone(value);
  } catch (e) {
    if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
      throw new DOMException(e.message, "DataCloneError");
    }
    throw e;
  }
}

return { structuredClone };
})();

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Separate behavior from data: remove functions, symbols, and platform objects before cloning and re-attach them on the receiving side.
  2. Clone only serializable state (plain objects, arrays, typed arrays, Maps/Sets, Dates, primitives) — the validator/reviver pattern.
  3. If class instances matter, convert to plain data first and reconstruct from the clone.
  4. Catch DOMException with name === 'DataCloneError' to emit a targeted error naming the offending key instead of a generic failure.

Example fix

// before
worker.postMessage(structuredClone(ctx)); // ctx has function handlers -> DataCloneError

// after
const { handlers, ...data } = ctx;
worker.postMessage(structuredClone(data));
Defensive patterns

Strategy: try-catch

Validate before calling

function isCloneable(v) {
  try { structuredClone(v); return true; } catch { return false; }
}
if (!isCloneable(state)) throw new Error('state contains uncloneable values');

Type guard

const isStructuredCloneable = (v) => {
  try { structuredClone(v); return true; } catch { return false; }
};

Try / catch

try {
  worker.postMessage(structuredClone(payload));
} catch (e) {
  if (e instanceof DOMException && e.name === 'DataCloneError') {
    const { handlers, ...data } = payload;
    worker.postMessage(structuredClone(data));
  } else throw e;
}

Prevention

When it happens

Trigger: structuredClone(() => {}); structuredClone({ cb: function () {} }); structuredClone(Symbol()); cloning an object holding a WebSocket, a Deno platform object, or any class instance whose graph reaches a function or native resource.

Common situations: Sending app state over postMessage/worker messages without stripping handlers; deep-cloning request contexts or ORM entities that embed connections; porting Electron-style IPC patterns where arbitrary objects were tolerated; caching objects that contain callbacks.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/8aa28a82c7b7607c. Report an issue: GitHub.