mongodb/node-mongodb-native · error · MongoCursorInUseError

Cursor is already initialized

Error message

Cursor is already initialized

What it means

Thrown as MongoCursorInUseError by AbstractCursor.throwIfInitialized() when a cursor-mutating builder method (filter, sort, limit, skip, addStage, project, map, etc.) is called after the cursor has already been initialized (i.e. iteration has begun). Once initialized=true, the cursor's command is effectively fixed and the driver forbids further structural changes. 'Cursor is already initialized' is the implicit message carried by MongoCursorInUseError.

Source

Thrown at src/cursor/abstract_cursor.ts:1091

      if (transformedDocument === null) {
        const TRANSFORM_TO_NULL_ERROR =
          'Cursor returned a `null` document, but the cursor is not exhausted.  Mapping documents to `null` is not supported in the cursor transform.';
        throw new MongoAPIError(TRANSFORM_TO_NULL_ERROR);
      }
      return transformedDocument;
    } catch (transformError) {
      try {
        await this.close();
      } catch (closeError) {
        squashError(closeError);
      }
      throw transformError;
    }
  }

  /** @internal */
  protected throwIfInitialized() {
    if (this.initialized) throw new MongoCursorInUseError();
  }
}

class ReadableCursorStream extends Readable {
  private _cursor: AbstractCursor;
  private _readInProgress = false;

  constructor(cursor: AbstractCursor) {
    super({
      objectMode: true,
      autoDestroy: false,
      highWaterMark: 1
    });
    this._cursor = cursor;
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  override _read(size: number): void {

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Set all options before the first await on the cursor (chain .filter().sort().limit() first, then iterate)
  2. If you need a changed query, call cursor.clone() to get a fresh un-initialized copy and modify that
  3. Do not reuse a cursor variable after iteration has started; create a new find()/aggregate()

Example fix

// before
const c = coll.find({});
await c.next();
c.sort({ x: 1 }); // throws MongoCursorInUseError
// after
const c = coll.find({}).sort({ x: 1 });
await c.next();
Defensive patterns

Strategy: validation

Validate before calling

function assertFresh(cursor) {
  // No public flag; track iteration yourself
  if (cursor.__started) throw new Error('cursor already initialized');
}
// Prefer: build the full query before iterating.

Try / catch

try {
  cursor.sort({ x: 1 });
} catch (e) {
  if (e instanceof MongoCursorInUseError) {
    cursor = cursor.clone().sort({ x: 1 }); // start fresh
  } else throw e;
}

Prevention

When it happens

Trigger: Calling coll.find(); then awaiting cursor.next(); then cursor.sort(...) or cursor.limit(...); also clone() is fine but chaining .limit().sort() after .next() throws. Reusing a cursor variable across two iterations also trips this.

Common situations: Building a query incrementally after a peek, reusing a cursor stored in a variable that was already partially consumed, or calling cursor.count()/explain() then mutating.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/acc895fcdff9d4a5.json. Report an issue: GitHub.