denoland/deno · error · TypeError
Invalid state: File-backed Blobs are not cloneable
Error message
Invalid state: File-backed Blobs are not cloneable
What it means
TypeError thrown by cloneBlobParts, the serialization hook used when a Blob (or File) is structured-cloned — via structuredClone, postMessage, or the host-object serialization path (ext/web/09_file.js). Blobs marked file-backed — created by markFileBackedBlob, which in Deno is applied to Blobs returned from node:fs openAsBlob (ext/node/polyfills/fs.ts) — are intentionally rejected by the clone serializer, matching Node.js behavior, because their backing storage is tied to the file handle's lifetime.
Source
Thrown at ext/web/09_file.js:735
for (let i = 0; i < parts.length; ++i) {
const part = parts[i];
if (ObjectPrototypeIsPrototypeOf(BlobPrototype, part)) {
getPartRefs(part, bag);
} else {
ArrayPrototypePush(bag, part);
}
}
return bag;
}
/**
* Clone blob part references in BlobStore and return serializable metadata.
* @param {Blob} blob
* @returns {{ uuid: string, size: number }[]}
*/
function cloneBlobParts(blob) {
if (blob[_fileBacked]) {
throw new TypeError("Invalid state: File-backed Blobs are not cloneable");
}
const refs = getPartRefs(blob);
const cloned = [];
for (let i = 0; i < refs.length; ++i) {
ArrayPrototypePush(cloned, op_blob_clone_part(refs[i]._id));
}
return cloned;
}
ObjectDefineProperty(Blob.prototype, core.hostObjectBrand, {
__proto__: null,
value: function () {
return {
type: "Blob",
mimeType: this[_type],
parts: cloneBlobParts(this),
size: this[_size],
};View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Materialize into a plain Blob before posting: const plain = new Blob([await blob.arrayBuffer()], { type: blob.type }).
- Send the bytes instead of the Blob: postMessage(await blob.bytes()) or transfer an ArrayBuffer.
- If only the file path matters, post the path string and re-open the blob in the receiving realm.
Example fix
// before
import { openAsBlob } from 'node:fs';
const blob = await openAsBlob('./big.bin');
worker.postMessage(blob); // TypeError: file-backed Blob not cloneable
// after
import { openAsBlob } from 'node:fs';
const blob = await openAsBlob('./big.bin');
const plain = new Blob([await blob.arrayBuffer()], { type: blob.type });
worker.postMessage(plain); // clones fine Defensive patterns
Strategy: fallback
Validate before calling
// File-backed provenance is not observable from JS (internal symbol),
// so convert anything that might be file-backed into a plain Blob first.
async function toCloneableBlob(maybeFileBacked) {
if (!maybeFileBacked) return new Blob();
return new Blob([await maybeFileBacked.arrayBuffer()], {
type: maybeFileBacked.type,
});
}
worker.postMessage(await toCloneableBlob(blob)); Try / catch
try {
worker.postMessage(blob);
} catch (err) {
if (err instanceof TypeError && /File-backed Blobs are not cloneable/.test(err.message)) {
const plain = new Blob([await blob.arrayBuffer()], { type: blob.type });
worker.postMessage(plain);
} else throw err;
} Prevention
- Treat every Blob from fs.openAsBlob/fsPromises.openAsBlob as non-transferable across realms.
- Post bytes (Uint8Array/ArrayBuffer) instead of Blobs when crossing worker boundaries.
- Materialize with new Blob([await b.arrayBuffer()], {type: b.type}) before structuredClone.
When it happens
Trigger: structuredClone(blob) or worker.postMessage(blob) where blob came from fs.openAsBlob()/fsPromises.openAsBlob(path); building a File from such a blob's parts and posting it; passing it through a MessageChannel.
Common situations: Node-compat code reading large files as Blobs for zero-copy-ish handling and then sending them to a Worker; libraries (e.g. file-upload helpers) that forward fs.openAsBlob results across realms; version changes where clone support for these blobs was removed to match Node.
Related errors
- Unsupported KeyObject type for structured clone: ${data.keyT
- DataCloneError
- DataCloneError
- DataCloneError
- DataCloneError
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/0d46d4cb88c36d7e.
Report an issue: GitHub.