{"record":{"id":"0d46d4cb88c36d7e","repo":"denoland/deno","slug":"invalid-state-file-backed-blobs-are-not-cloneable","errorCode":null,"errorMessage":"Invalid state: File-backed Blobs are not cloneable","messagePattern":"Invalid state: File-backed Blobs are not cloneable","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/09_file.js","lineNumber":735,"sourceCode":"  for (let i = 0; i < parts.length; ++i) {\n    const part = parts[i];\n    if (ObjectPrototypeIsPrototypeOf(BlobPrototype, part)) {\n      getPartRefs(part, bag);\n    } else {\n      ArrayPrototypePush(bag, part);\n    }\n  }\n  return bag;\n}\n\n/**\n * Clone blob part references in BlobStore and return serializable metadata.\n * @param {Blob} blob\n * @returns {{ uuid: string, size: number }[]}\n */\nfunction cloneBlobParts(blob) {\n  if (blob[_fileBacked]) {\n    throw new TypeError(\"Invalid state: File-backed Blobs are not cloneable\");\n  }\n  const refs = getPartRefs(blob);\n  const cloned = [];\n  for (let i = 0; i < refs.length; ++i) {\n    ArrayPrototypePush(cloned, op_blob_clone_part(refs[i]._id));\n  }\n  return cloned;\n}\n\nObjectDefineProperty(Blob.prototype, core.hostObjectBrand, {\n  __proto__: null,\n  value: function () {\n    return {\n      type: \"Blob\",\n      mimeType: this[_type],\n      parts: cloneBlobParts(this),\n      size: this[_size],\n    };","sourceCodeStart":717,"sourceCodeEnd":753,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/09_file.js#L717-L753","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nimport { openAsBlob } from 'node:fs';\nconst blob = await openAsBlob('./big.bin');\nworker.postMessage(blob); // TypeError: file-backed Blob not cloneable\n\n// after\nimport { openAsBlob } from 'node:fs';\nconst blob = await openAsBlob('./big.bin');\nconst plain = new Blob([await blob.arrayBuffer()], { type: blob.type });\nworker.postMessage(plain); // clones fine","handlingStrategy":"fallback","validationCode":"// File-backed provenance is not observable from JS (internal symbol),\n// so convert anything that might be file-backed into a plain Blob first.\nasync function toCloneableBlob(maybeFileBacked) {\n  if (!maybeFileBacked) return new Blob();\n  return new Blob([await maybeFileBacked.arrayBuffer()], {\n    type: maybeFileBacked.type,\n  });\n}\nworker.postMessage(await toCloneableBlob(blob));","typeGuard":null,"tryCatchPattern":"try {\n  worker.postMessage(blob);\n} catch (err) {\n  if (err instanceof TypeError && /File-backed Blobs are not cloneable/.test(err.message)) {\n    const plain = new Blob([await blob.arrayBuffer()], { type: blob.type });\n    worker.postMessage(plain);\n  } else throw err;\n}","preventionTips":["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."],"tags":["blob","structured-clone","postmessage","node-compat","file"],"backgroundTag":"blob-not-cloneable","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}