mongodb/node-mongodb-native · error · MongoGridFSStreamError
Options cannot be changed after the stream is initialized
Error message
Options cannot be changed after the stream is initialized
What it means
GridFSBucketReadStream.start() and end() mutate read-range options, but only before the stream begins reading. throwIfInitialized (src/gridfs/download.ts:211) checks the internal init flag and throws MongoGridFSStreamError once the stream has entered flowing mode (e.g. after a 'data' listener is attached or _read has run). This prevents inconsistent range state after bytes have been requested.
Solutions
- Call start() and end() synchronously after openDownloadStream() and before attaching any data listener or piping.
- Pass start and end directly in openDownloadStream(id, { start, end }) instead of using the chained setters.
- If you need a different range, open a new stream rather than reconfiguring an existing one.
Example fix
// before
const s = bucket.openDownloadStream(id);
s.on('data', chunk => {});
s.start(100); // throws
// after
const s = bucket.openDownloadStream(id, { start: 100 });
s.on('data', chunk => {}); Defensive patterns
Strategy: validation
Validate before calling
function openRangeStream(bucket, id, range) {
// pass range at construction; never mutate after
return bucket.openDownloadStream(id, range);
} Type guard
function isUninitialized(stream: GridFSBucketReadStream): boolean {
return !(stream as any).s?.init;
} Try / catch
try {
stream.start(n);
} catch (e) {
if (e instanceof MongoGridFSStreamError && /cannot be changed after/.test(e.message)) {
// open a fresh stream with the desired range
}
throw e;
} Prevention
- Pass start/end in openDownloadStream options rather than using the chained setters.
- Never attach data listeners before configuring the range.
- Open a new stream for each distinct range read.
When it happens
Trigger: Calling stream.start(n) or stream.end(n) after attaching a 'data' listener, after piping the stream, or after awaiting any consumption. Calling start()/end() after the stream has emitted its first chunk.
Common situations: Attaching on('data') then conditionally calling start() based on metadata received from the 'file' event. Reusing a stream instance and trying to reconfigure it for a second read.
Related errors
- Cannot abort a stream that has already completed
- Cannot call abort() on a stream twice
- End option must be defined
- Start option must be defined
- Stream end ( ) must not be more than the length of the file…
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/7c675547c72b1a82.
Report an issue: GitHub.
Appendix: source
Thrown at src/gridfs/download.ts:213
return this;
}
/**
* Marks this stream as aborted (will never push another `data` event)
* and kills the underlying cursor. Will emit the 'end' event, and then
* the 'close' event once the cursor is successfully killed.
*/
async abort(): Promise<void> {
this.push(null);
this.destroy();
const remainingTimeMS = this.s.timeoutContext?.getRemainingTimeMSOrThrow();
await this.s.cursor?.close({ timeoutMS: remainingTimeMS });
}
}
function throwIfInitialized(stream: GridFSBucketReadStream): void {
if (stream.s.init) {
throw new MongoGridFSStreamError('Options cannot be changed after the stream is initialized');
}
}
function doRead(stream: GridFSBucketReadStream): void {
if (stream.destroyed) return;
if (!stream.s.cursor) return;
if (!stream.s.file) return;
const handleReadResult = (doc: Document | null) => {
if (stream.destroyed) return;
if (!doc) {
stream.push(null);
stream.s.cursor?.close().then(undefined, error => stream.destroy(error));
return;
}
View on GitHub (pinned to dce7939f86)