{"record":{"id":"3c8c00e89813ffa1","repo":"denoland/deno","slug":"readablebytestreamcontroller-s-stream-is-not-in-a","errorCode":null,"errorMessage":"ReadableByteStreamController's stream is not in a readable state","messagePattern":"ReadableByteStreamController's stream is not in a readable state","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":6838,"sourceCode":"  get byobRequest() {\n    webidl.assertBranded(this, ReadableByteStreamControllerPrototype);\n    return readableByteStreamControllerGetBYOBRequest(this);\n  }\n\n  /** @returns {number | null} */\n  get desiredSize() {\n    webidl.assertBranded(this, ReadableByteStreamControllerPrototype);\n    return readableByteStreamControllerGetDesiredSize(this);\n  }\n\n  /** @returns {void} */\n  close() {\n    webidl.assertBranded(this, ReadableByteStreamControllerPrototype);\n    if (this[_closeRequested] === true) {\n      throw new TypeError(\"Closed already requested.\");\n    }\n    if (this[_stream][_state] !== \"readable\") {\n      throw new TypeError(\n        \"ReadableByteStreamController's stream is not in a readable state\",\n      );\n    }\n    readableByteStreamControllerClose(this);\n  }\n\n  /**\n   * @param {ArrayBufferView} chunk\n   * @returns {void}\n   */\n  enqueue(chunk) {\n    webidl.assertBranded(this, ReadableByteStreamControllerPrototype);\n    const prefix =\n      \"Failed to execute 'enqueue' on 'ReadableByteStreamController'\";\n    webidl.requiredArguments(arguments.length, 1, prefix);\n    const arg1 = \"Argument 1\";\n    chunk = webidl.converters.ArrayBufferView(chunk, prefix, arg1);\n    let buffer, byteLength;","sourceCodeStart":6820,"sourceCodeEnd":6856,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L6820-L6856","documentation":"Thrown by ReadableByteStreamController.close() when the controller's stream state is not \"readable\" (ext/web/06_streams.js), i.e. the stream is already \"closed\" or \"errored\". Once a stream has been closed by a previous close, errored via controller.error(e), or canceled by its reader, its state leaves \"readable\" and no further close is accepted.","triggerScenarios":"Calling close() after controller.error(e) in an error path; calling close() after the consumer called stream.cancel(); closing after the stream already reached \"closed\" state (e.g. close after close where the first close completed immediately).","commonSituations":"Error handling that calls error(e) and then generic cleanup calls close(); server code closing a stream after a client disconnect already canceled it; retry wrappers that close on exit while the stream ended earlier.","solutions":["Pick one terminal operation per stream: either close() on success or error(e) on failure, never both.","Before closing, check controller.desiredSize: null means errored, 0 strongly suggests already-closed; treat both as 'do not close'.","Propagate the reader's cancel signal to your producer (implement cancel() in the underlying source) so cleanup knows not to close.","Wrap close() in try/catch TypeError and ignore when the stream already ended."],"exampleFix":"// before\ntry {\n  controller.enqueue(chunk);\n  controller.close();\n} catch (e) {\n  controller.error(e);\n  controller.close(); // throws: stream is errored\n}\n\n// after\ntry {\n  controller.enqueue(chunk);\n  controller.close();\n} catch (e) {\n  controller.error(e); // terminal; do not also close\n}","handlingStrategy":"try-catch","validationCode":"// desiredSize: null => errored, 0 => likely closed (verify with your\n// own state). Only close when the stream is provably still readable.\nconst ds = controller.desiredSize;\nif (ds !== null && ds > 0 && !this.done) {\n  controller.close();\n}","typeGuard":null,"tryCatchPattern":"try {\n  controller.close();\n} catch (err) {\n  if (err instanceof TypeError && /not in a readable state/.test(err.message)) {\n    // stream already closed/errored/canceled — nothing to do\n  } else throw err;\n}","preventionTips":["error(e) and close() are mutually exclusive terminals; call exactly one.","Propagate reader cancellation into your source and stop closing after cancel.","Check controller.desiredSize === null (errored) before closing defensively."],"tags":["streams","readable-stream","byte-stream","stream-state"],"backgroundTag":"stream-close-after-error","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}