{"record":{"id":"d602ad63a769151f","repo":"denoland/deno","slug":"byteswritten-must-be-0-when-calling-respond-on","errorCode":null,"errorMessage":"\"bytesWritten\" must be 0 when calling respond() on a closed stream: received ${bytesWritten}","messagePattern":"\"bytesWritten\" must be 0 when calling respond\\(\\) on a closed stream: received (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":2593,"sourceCode":"    }\n  }\n  controller[_pendingPullIntos].enqueue(pullIntoDescriptor);\n  readableStreamAddReadIntoRequest(stream, readIntoRequest);\n  readableByteStreamControllerCallPullIfNeeded(controller);\n}\n\n/**\n * @param {ReadableByteStreamController} controller\n * @param {number} bytesWritten\n * @returns {void}\n */\nfunction readableByteStreamControllerRespond(controller, bytesWritten) {\n  assert(controller[_pendingPullIntos].size !== 0);\n  const firstDescriptor = controller[_pendingPullIntos].peek();\n  const state = controller[_stream][_state];\n  if (state === \"closed\") {\n    if (bytesWritten !== 0) {\n      throw new TypeError(\n        `\"bytesWritten\" must be 0 when calling respond() on a closed stream: received ${bytesWritten}`,\n      );\n    }\n  } else {\n    assert(state === \"readable\");\n    if (bytesWritten === 0) {\n      throw new TypeError(\n        '\"bytesWritten\" must be greater than 0 when calling respond() on a readable stream',\n      );\n    }\n    if (\n      (firstDescriptor.bytesFilled + bytesWritten) >\n        // deno-lint-ignore deno-internal/prefer-primordials\n        firstDescriptor.byteLength\n    ) {\n      throw new RangeError('\"bytesWritten\" out of range');\n    }\n  }","sourceCodeStart":2575,"sourceCodeEnd":2611,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L2575-L2611","documentation":"ReadableStreamBYOBRequest.respond() was called with a non-zero bytesWritten while the stream is in the 'closed' state. Once a byte stream is closed there is no pending consumer buffer left to fill, so the spec only permits respond(0) as a no-op acknowledgment. In practice this means code responded after controller.close() already ran.","triggerScenarios":"controller.close() executes and then a completion callback (OS read, socket event, promise chain) still calls byobRequest.respond(n > 0); responding from a stale byobRequest captured in an earlier pull(); an error path that closes the stream and then falls through to the success path that responds.","commonSituations":"File/socket adapters where EOF-triggered close races an in-flight read completion; async write callbacks resolving after close; source code holding a request object across pulls.","solutions":["Check for zero-byte/EOF reads and call controller.close() instead of responding; never respond with bytes after close.","Fetch controller.byobRequest fresh inside each pull() and respond exactly once, only while it is non-null.","Sequence I/O: await the pending read before closing the stream.","On a possibly-closed stream, respond(0) or skip — never with a byte count."],"exampleFix":"// before\nconst done = bytesWritten === 0;\nif (done) controller.close();\nbyob.respond(bytesWritten); // done && bytesWritten > 0 -> TypeError\n\n// after\nconst done = bytesWritten === 0;\nif (done) { controller.close(); return; } // EOF: close, do not respond\nbyob.respond(bytesWritten);","handlingStrategy":"validation","validationCode":"// helper: respond safely on a possibly-closed byte stream\nfunction respondSafe(controller, n) {\n  const byob = controller.byobRequest;\n  if (byob === null) return; // no live request (closed or none pending)\n  if (n === 0) return;       // nothing written: not a response\n  byob.respond(Math.min(n, byob.view.byteLength));\n}","typeGuard":null,"tryCatchPattern":"try {\n  byob.respond(n);\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('closed stream')) {\n    return; // stream already closed: nothing left to deliver\n  }\n  throw e;\n}","preventionTips":["Respond at most once per pull(), in the same tick as the read that filled the view.","Await pending I/O before calling controller.close().","Never cache byobRequest across pulls — read controller.byobRequest fresh each time."],"tags":["readable-stream","byob-reader","respond","stream-state","eof"],"backgroundTag":"byob-request-respond-misuse","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T04:17:50.494Z"}