{"record":{"id":"c7323f18835d2bd9","repo":"denoland/deno","slug":"chunk-s-buffer-is-detached-and-so-cannot-be-enqueu","errorCode":null,"errorMessage":"Chunk's buffer is detached and so cannot be enqueued","messagePattern":"Chunk's buffer is detached and so cannot be enqueued","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":1804,"sourceCode":"    buffer = TypedArrayPrototypeGetBuffer(/** @type {Uint8Array}} */ (chunk));\n    byteLength = TypedArrayPrototypeGetByteLength(\n      /** @type {Uint8Array} */ (chunk),\n    );\n    byteOffset = TypedArrayPrototypeGetByteOffset(\n      /** @type {Uint8Array} */ (chunk),\n    );\n  } else {\n    buffer = DataViewPrototypeGetBuffer(/** @type {DataView} */ (chunk));\n    byteLength = DataViewPrototypeGetByteLength(\n      /** @type {DataView} */ (chunk),\n    );\n    byteOffset = DataViewPrototypeGetByteOffset(\n      /** @type {DataView} */ (chunk),\n    );\n  }\n\n  if (isDetachedBuffer(buffer)) {\n    throw new TypeError(\n      \"Chunk's buffer is detached and so cannot be enqueued\",\n    );\n  }\n  const transferredBuffer = ArrayBufferPrototypeTransferToFixedLength(buffer);\n  if (controller[_pendingPullIntos].size !== 0) {\n    const firstPendingPullInto = controller[_pendingPullIntos].peek();\n    // deno-lint-ignore deno-internal/prefer-primordials\n    if (isDetachedBuffer(firstPendingPullInto.buffer)) {\n      throw new TypeError(\n        \"The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk\",\n      );\n    }\n    readableByteStreamControllerInvalidateBYOBRequest(controller);\n    firstPendingPullInto.buffer = ArrayBufferPrototypeTransferToFixedLength(\n      // deno-lint-ignore deno-internal/prefer-primordials\n      firstPendingPullInto.buffer,\n    );\n    if (firstPendingPullInto.readerType === \"none\") {","sourceCodeStart":1786,"sourceCodeEnd":1822,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L1786-L1822","documentation":"Thrown by ReadableByteStreamController.enqueue() on a byte stream (new ReadableStream({ type: 'bytes' })) when the chunk is a TypedArray or DataView whose backing ArrayBuffer is detached. Enqueue on a byte stream takes ownership of the chunk's buffer by transferring it (ArrayBufferPrototypeTransferToFixedLength) into the stream's queue, which is impossible once the buffer is detached. Buffers become detached via postMessage/structuredClone transfer lists, ArrayBuffer.prototype.transfer()/transferToFixedLength(), and similar move operations.","triggerScenarios":"controller.enqueue(view) after worker.postMessage(view.buffer, [view.buffer]); enqueueing a view whose buffer was already moved with buf.transfer(); enqueueing the same view twice (the first enqueue transfers and detaches it); enqueueing a view whose buffer a previous respond()/respondWithNewView() already consumed.","commonSituations":"Zero-copy pipelines that both enqueue into a ReadableStream and ship buffers to a Worker or WASM; buffer pools reused across streams; right-sizing buffers with transfer() before enqueue; porting Node Buffer code where enqueue does not transfer ownership.","solutions":["Enqueue a copy (controller.enqueue(view.slice())) when the original buffer must be reused or transferred elsewhere.","Never put a buffer on a postMessage/structuredClone transfer list while a stream still owns views into it.","Treat any view passed to enqueue() as consumed — never enqueue or write it again.","Guard before enqueue: if (chunk.buffer.detached === true) rebuild the chunk from a retained copy."],"exampleFix":"// before\nconst view = new Uint8Array(buf);\nworker.postMessage(buf, [buf]); // detaches buf\ncontroller.enqueue(view);        // TypeError: Chunk's buffer is detached\n\n// after\nconst view = new Uint8Array(buf);\ncontroller.enqueue(view.slice()); // stream takes the copy\nworker.postMessage(buf, [buf]);   // safe to transfer the original","handlingStrategy":"validation","validationCode":"// run before controller.enqueue(chunk) on a byte stream\nfunction ensureEnqueueable(chunk) {\n  if (chunk.buffer.detached === true) {\n    throw new Error('chunk buffer is detached — enqueue a retained copy instead');\n  }\n}\nensureEnqueueable(chunk);\ncontroller.enqueue(chunk);","typeGuard":"function hasLiveBuffer(view) {\n  return (view instanceof Uint8Array || view instanceof DataView)\n    && view.buffer.detached !== true;\n}","tryCatchPattern":"try {\n  controller.enqueue(chunk);\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('detached')) {\n    controller.error(e); // the data is gone; fail the stream loudly\n  }\n  throw e;\n}","preventionTips":["Treat any view passed to enqueue()/respond() as transferred: use it exactly once.","Copy (slice) before enqueue when the buffer is shared, pooled, or destined for a transfer list.","After ArrayBuffer.transfer(), only the returned new buffer is usable.","Check chunk.buffer.detached in debug logs when binary pipelines misbehave."],"tags":["readable-stream","byte-stream","arraybuffer","detached-buffer","enqueue"],"backgroundTag":"detached-arraybuffer","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}