mongodb/node-mongodb-native · error · MongoTailableCursorError

Tailable cursor does not support batchSize

Error message

Tailable cursor does not support batchSize

What it means

Thrown as a MongoTailableCursorError (a subclass of MongoAPIError) from batchSize() when cursorOptions.tailable is true. A tailable cursor follows the tail of a capped collection and must not pin itself to a fixed batch size, because doing so would interfere with the await/blocking semantics that let tailing work; the driver rejects batchSize on tailable cursors to prevent this. The guard runs before the integer check, and only when the cursor is not yet initialized.

Solutions

  1. Remove the batchSize call/option for tailable cursors; rely on the server default batch sizing.
  2. If you need backpressure control on a tailable cursor, manage it at the consumer side (e.g. stream highWaterMark) rather than via batchSize.
  3. Split your cursor-builder so tailable and non-tailable paths do not share the batchSize configuration.

Example fix

// before: batchSize on a tailable cursor
const cursor = collection.find(filter, { tailable: true, awaitData: true });
cursor.batchSize(100); // throws MongoTailableCursorError

// after: drop batchSize for tailable cursors
const cursor = collection.find(filter, { tailable: true, awaitData: true });
Defensive patterns

Strategy: validation

Validate before calling

if (opts.tailable && opts.batchSize != null) {
  throw new RangeError('batchSize is not supported on tailable cursors');
}

Prevention

When it happens

Trigger: Building a cursor with addCursorFlag('tailable', true) (or { tailable: true }) and then calling cursor.batchSize(N); configuring a tailable change-stream-style cursor and trying to tune batch size.

Common situations: Reusing a generic cursor-builder helper that always sets batchSize, on a tailable cursor; enabling tailable after setting batchSize in a chained config.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/62767a4690e0d0ba. Report an issue: GitHub.

Appendix: source

Thrown at src/cursor/abstract_cursor.ts:804

  maxTimeMS(value: number): this {
    this.throwIfInitialized();
    if (typeof value !== 'number') {
      throw new MongoInvalidArgumentError('Argument for maxTimeMS must be a number');
    }

    this.cursorOptions.maxTimeMS = value;
    return this;
  }

  /**
   * Set the batch size for the cursor.
   *
   * @param value - The number of documents to return per batch. See {@link https://www.mongodb.com/docs/manual/reference/command/find/|find command documentation}.
   */
  batchSize(value: number): this {
    this.throwIfInitialized();
    if (this.cursorOptions.tailable) {
      throw new MongoTailableCursorError('Tailable cursor does not support batchSize');
    }

    if (typeof value !== 'number') {
      throw new MongoInvalidArgumentError('Operation "batchSize" requires an integer');
    }

    this.cursorOptions.batchSize = value;
    return this;
  }

  /**
   * Rewind this cursor to its uninitialized state. Any options that are present on the cursor will
   * remain in effect. Iterating this cursor will cause new queries to be sent to the server, even
   * if the resultant data has already been retrieved by this cursor.
   */
  rewind(): void {
    if (this.timeoutContext && this.timeoutContext.owner !== this) {
      throw new MongoAPIError(`Cannot rewind cursor that does not own its timeout context.`);

View on GitHub (pinned to dce7939f86)