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

  1. Call start() and end() synchronously after openDownloadStream() and before attaching any data listener or piping.
  2. Pass start and end directly in openDownloadStream(id, { start, end }) instead of using the chained setters.
  3. 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

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


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)