{"record":{"id":"524c1b54bd98dfeb","repo":"denoland/deno","slug":"closed-already-requested","errorCode":null,"errorMessage":"Closed already requested.","messagePattern":"Closed already requested\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":6835,"sourceCode":"  }\n\n  /** @returns {ReadableStreamBYOBRequest | null} */\n  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);","sourceCodeStart":6817,"sourceCodeEnd":6853,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L6817-L6853","documentation":"Thrown by ReadableByteStreamController.close() when this[_closeRequested] is already true (ext/web/06_streams.js). Closing a byte stream is single-shot: the first close() sets the close-requested flag, and any second close() on the same controller is a state-machine violation and throws a TypeError, per the WHATWG Streams spec.","triggerScenarios":"Calling controller.close() twice from start()/pull() logic; a close() in the success path plus another close() in a finally block; two branches of a producer (EOF branch and error-cleanup branch) both closing.","commonSituations":"Producers with try/finally cleanup that also close on normal EOF; recursive or event-driven push code where multiple callbacks race to close; refactors that add a second close 'for safety'.","solutions":["Call close() exactly once per controller; track it with a boolean (e.g. let closed = false; if (!closed) { closed = true; controller.close(); }).","Restructure so only the EOF path of the source closes the controller; cleanup paths should only run if close was not yet requested.","Wrap close() in a guarded helper so all call sites share one state check."],"exampleFix":"// before\ntry {\n  controller.enqueue(chunk);\n  controller.close();\n} finally {\n  controller.close(); // second close -> TypeError\n}\n\n// after\nlet closed = false;\nconst closeOnce = () => { if (!closed) { closed = true; controller.close(); } };\ntry {\n  controller.enqueue(chunk);\n  closeOnce();\n} finally {\n  closeOnce(); // no-op if already closed\n}","handlingStrategy":"validation","validationCode":"// closeRequested is not directly observable — track it yourself.\nlet closeRequested = false;\nfunction closeOnce(controller) {\n  if (closeRequested) return;\n  closeRequested = true;\n  controller.close();\n}","typeGuard":null,"tryCatchPattern":"try {\n  controller.close();\n} catch (err) {\n  if (err instanceof TypeError && err.message === 'Closed already requested.') return; // benign\n  throw err;\n}","preventionTips":["Route every close through one guarded helper with a shared flag.","Only the EOF path of your source should close; cleanup paths must not.","Review try/finally blocks for a second, unconditional close()."],"tags":["streams","readable-stream","byte-stream","double-close"],"backgroundTag":"stream-double-close","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}