denoland/deno · error · TypeError
Cannot enqueue chunk after a close has been requested
Error message
Cannot enqueue chunk after a close has been requested
What it means
Thrown by ReadableByteStreamController.enqueue(chunk) when this[_closeRequested] is true (ext/web/06_streams.js). After close() has been called, the stream has committed to ending and accepts no more chunks; enqueueing past that point is a producer contract violation and throws a TypeError.
Source
Thrown at ext/web/06_streams.js:6885
}
if (byteLength === 0) {
throw webidl.makeException(
TypeError,
"Length must be non-zero",
prefix,
arg1,
);
}
if (getArrayBufferByteLength(buffer) === 0) {
throw webidl.makeException(
TypeError,
"Buffer length must be non-zero",
prefix,
arg1,
);
}
if (this[_closeRequested] === true) {
throw new TypeError(
"Cannot enqueue chunk after a close has been requested",
);
}
if (this[_stream][_state] !== "readable") {
throw new TypeError(
"Cannot enqueue chunk when underlying stream is not readable",
);
}
return readableByteStreamControllerEnqueue(this, chunk);
}
/**
* @param {any=} e
* @returns {void}
*/
error(e = undefined) {
webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
if (e !== undefined) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Enforce single-producer discipline: after any code path calls close(), no path may enqueue — gate both with a shared `closed`/`done` flag.
- Only close when the source is fully drained; buffer late chunks and decide close vs enqueue in one place.
- Check readiness before enqueueing: skip when the source signaled end or the flag says closed.
Example fix
// before
source.on("end", () => controller.close());
source.on("data", (d) => controller.enqueue(d)); // may fire after close
// after
let ended = false;
source.on("end", () => { ended = true; controller.close(); });
source.on("data", (d) => { if (!ended) controller.enqueue(d); }); Defensive patterns
Strategy: validation
Validate before calling
let done = false;
function push(controller, chunk) {
if (done) return false; // closed: stop producing
controller.enqueue(chunk);
return true;
}
function finish(controller) {
if (!done) { done = true; controller.close(); }
} Prevention
- Gate every enqueue with the same flag that close() sets.
- Close only from the single EOF path; never from racing event handlers.
- Buffer late-arriving chunks and drop them (or log) once done is set.
When it happens
Trigger: A loop or async callback calling enqueue() after the code path already called close(); an EOF branch that closes while another racing producer callback still enqueues; closing on empty source then pushing late-arriving data.
Common situations: Event-driven producers (file watchers, sockets) that close on idle but receive events afterwards; multiple pending pull() invocations where one closes; cleanup that closes early while buffered writes are still flushed.
Related errors
- Closed already requested.
- ReadableByteStreamController's stream is not in a readable s
- Cannot enqueue chunk when underlying stream is not readable
- Chunk's buffer is detached and so cannot be enqueued
- "autoAllocateChunkSize" must be greater than 0
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/262e788932757009.
Report an issue: GitHub.