{"record":{"id":"34035578e9677ca3","repo":"denoland/deno","slug":"cannot-enqueue-chunk-when-underlying-stream-is-not","errorCode":null,"errorMessage":"Cannot enqueue chunk when underlying stream is not readable","messagePattern":"Cannot enqueue chunk when underlying stream is not readable","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":6890,"sourceCode":"        prefix,\n        arg1,\n      );\n    }\n    if (getArrayBufferByteLength(buffer) === 0) {\n      throw webidl.makeException(\n        TypeError,\n        \"Buffer length must be non-zero\",\n        prefix,\n        arg1,\n      );\n    }\n    if (this[_closeRequested] === true) {\n      throw new TypeError(\n        \"Cannot enqueue chunk after a close has been requested\",\n      );\n    }\n    if (this[_stream][_state] !== \"readable\") {\n      throw new TypeError(\n        \"Cannot enqueue chunk when underlying stream is not readable\",\n      );\n    }\n    return readableByteStreamControllerEnqueue(this, chunk);\n  }\n\n  /**\n   * @param {any=} e\n   * @returns {void}\n   */\n  error(e = undefined) {\n    webidl.assertBranded(this, ReadableByteStreamControllerPrototype);\n    if (e !== undefined) {\n      e = webidl.converters.any(e);\n    }\n    readableByteStreamControllerError(this, e);\n  }\n","sourceCodeStart":6872,"sourceCodeEnd":6908,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L6872-L6908","documentation":"Thrown by ReadableByteStreamController.enqueue(chunk) when the stream's state is not \"readable\" (ext/web/06_streams.js) — the stream was canceled by its reader, errored via controller.error(), or already closed. Chunks cannot be delivered to a non-readable stream, so enqueue is rejected.","triggerScenarios":"The consumer calls stream.cancel() (e.g. aborted fetch, client disconnect) while the producer keeps enqueueing; enqueueing after controller.error(e) already errored the stream; enqueueing after the stream closed.","commonSituations":"Long-running producers that ignore cancellation (no cancel() implementation in the underlying source); server handlers whose client aborted mid-stream; error paths that error the stream but leave timers/callbacks pushing data.","solutions":["Implement cancel(reason) in the underlying source and stop enqueueing once it fires.","Before enqueueing, check controller.desiredSize — null means errored; treat 0-with-no-progress plus a done flag as ended; on any terminal signal stop producing.","Route all enqueue calls through one helper that first checks your producer's done/canceled state.","Clear timers/callbacks in the cancel path so no enqueue can race cancellation."],"exampleFix":"// before\nnew ReadableStream({\n  start(c) { setInterval(() => c.enqueue(poll()), 10); }, // keeps firing after cancel\n});\n\n// after\nnew ReadableStream({\n  start(c) {\n    this.t = setInterval(() => { if (!this.done) c.enqueue(poll()); }, 10);\n  },\n  cancel() { this.done = true; clearInterval(this.t); },\n});","handlingStrategy":"validation","validationCode":"// Stop when the consumer canceled: desiredSize is null once errored,\n// and cancellation closes the stream. Combine with your own done flag.\nfunction safeEnqueue(controller, chunk, done) {\n  if (done || controller.desiredSize === null) {\n    stopProducing(); // cancel timers, unsubscribe events\n    return;\n  }\n  controller.enqueue(chunk);\n}","typeGuard":null,"tryCatchPattern":"try {\n  controller.enqueue(chunk);\n} catch (err) {\n  if (err instanceof TypeError && /not readable/.test(err.message)) stopProducing();\n  else throw err;\n}","preventionTips":["Implement cancel(reason) in every ReadableStream underlying source you write.","Shut down timers/event subscriptions in the cancel path so no enqueue races it.","Treat reader cancellation as a hard stop for the producer."],"tags":["streams","readable-stream","byte-stream","stream-canceled"],"backgroundTag":"stream-enqueue-after-close","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}