{"record":{"id":"bf25087cd62e86d2","repo":"denoland/deno","slug":"the-stream-controller-cannot-close-or-enqueue","errorCode":null,"errorMessage":"The stream controller cannot close or enqueue","messagePattern":"The stream controller cannot close or enqueue","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":7041,"sourceCode":"\n  constructor(brand = undefined) {\n    if (brand !== _brand) {\n      webidl.illegalConstructor();\n    }\n    this[_brand] = _brand;\n  }\n\n  /** @returns {number | null} */\n  get desiredSize() {\n    webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);\n    return readableStreamDefaultControllerGetDesiredSize(this);\n  }\n\n  /** @returns {void} */\n  close() {\n    webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);\n    if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {\n      throw new TypeError(\"The stream controller cannot close or enqueue\");\n    }\n    readableStreamDefaultControllerClose(this);\n  }\n\n  /**\n   * @param {R} chunk\n   * @returns {void}\n   */\n  enqueue(chunk = undefined) {\n    webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);\n    if (chunk !== undefined) {\n      chunk = webidl.converters.any(chunk);\n    }\n    if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {\n      throw new TypeError(\"The stream controller cannot close or enqueue\");\n    }\n    readableStreamDefaultControllerEnqueue(this, chunk);\n  }","sourceCodeStart":7023,"sourceCodeEnd":7059,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L7023-L7059","documentation":"Thrown by ReadableStreamDefaultController.close() when readableStreamDefaultControllerCanCloseOrEnqueue(this) returns false (ext/web/06_streams.js): either close was already requested, the stream was canceled, or it was errored. The default (value-mode) controller only permits one terminal close while the stream is still readable.","triggerScenarios":"Calling close() twice; calling close() after enqueue-then-close in start(); calling close() after error(e) or after the reader canceled the stream; closing in a finally that also runs after a normal close.","commonSituations":"Transform/source implementations with cleanup code that closes unconditionally; double close across async boundaries (e.g. in both pull() completion and an end event); test code that closes stub controllers twice.","solutions":["Close exactly once: guard with a `closed` boolean shared by all paths that can close.","Only call close() from the single code path that detects source EOF.","If state is uncertain, wrap close() in try/catch TypeError and treat 'cannot close or enqueue' as already-ended."],"exampleFix":"// before\nfunction push(controller, chunk, end) {\n  if (chunk) controller.enqueue(chunk);\n  if (end) controller.close();\n}\n// ...two calls with end=true throw on the second\n\n// after\nlet closed = false;\nfunction push(controller, chunk, end) {\n  if (closed) return;\n  if (chunk) controller.enqueue(chunk);\n  if (end) { closed = true; controller.close(); }\n}","handlingStrategy":"validation","validationCode":"// desiredSize is null when errored and 0 when closed — combined with\n// an own close flag this is a reliable pre-check for close().\nlet closed = false;\nfunction closeIfOpen(controller) {\n  if (closed || controller.desiredSize === null) return;\n  closed = true;\n  controller.close();\n}","typeGuard":null,"tryCatchPattern":"try {\n  controller.close();\n} catch (err) {\n  if (err instanceof TypeError && err.message === 'The stream controller cannot close or enqueue') return;\n  throw err;\n}","preventionTips":["Use one guarded close helper for all call sites.","Let only the EOF branch of your producer close the controller.","In tests of stream glue code, assert close is called exactly once."],"tags":["streams","readable-stream","default-controller","double-close"],"backgroundTag":"stream-double-close","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}