mongodb/node-mongodb-native · error · MongoRuntimeError

Unable to iterate cursor with no id

Error message

Unable to iterate cursor with no id

What it means

Thrown as a MongoRuntimeError by GetMoreOperation.buildCommand when the cursorId is null or zero (this.cursorId.isZero()). A zero cursor id means the server has already closed the cursor (it returned id 0 indicating no more batches), so issuing getMore is invalid. This usually surfaces as an attempt to iterate an already-exhausted or closed cursor.

Solutions

  1. Stop iterating once the cursor is exhausted (for-await-of ends naturally; check (await cursor.next()) === null).
  2. Do not reuse a cursor after it has been closed or fully iterated; create a new query instead.
  3. Avoid concurrent iteration of the same cursor.

Example fix

// before
const cursor = coll.find({});
await cursor.forEach(()=>{});
await cursor.next(); // cursor exhausted -> error

// after
const cursor = coll.find({});
await cursor.forEach(()=>{});
// start a fresh query if you need the data again
const fresh = coll.find({});
Defensive patterns

Strategy: validation

Validate before calling

import type { FindCursor } from 'mongodb';

async function safelyNext<T>(cursor: FindCursor<T>): Promise<T | null> {
  // Respect cursor exhaustion; do not call next after the cursor reports closed
  if (cursor.closed) return null;
  return cursor.next();
}

Try / catch

try {
  await cursor.next();
} catch (err) {
  if (err instanceof MongoRuntimeError && /no id/.test(err.message)) {
    // cursor already exhausted; stop iterating
  } else throw err;
}

Prevention

When it happens

Trigger: Continuing to call cursor.next() / for-await after the cursor has been fully drained (server returned cursorId 0), or calling .next() on a cursor that was explicitly closed. The check is at get_more.ts:57.

Common situations: Looping over a cursor without checking for done; reusing a cursor after iteration completed; concurrency where one consumer closes the cursor while another iterates; transforming a cursor to an array then iterating again.

Related errors


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

Appendix: source

Thrown at src/operations/get_more.ts:58

  cursorId: Long;
  override options: GetMoreOptions;

  constructor(ns: MongoDBNamespace, cursorId: Long, server: Server, options: GetMoreOptions) {
    super(options);

    this.options = options;
    this.ns = ns;
    this.cursorId = cursorId;
    this.server = server;
  }

  override get commandName() {
    return 'getMore' as const;
  }

  override buildCommand(_connection: Connection): Document {
    if (this.cursorId == null || this.cursorId.isZero()) {
      throw new MongoRuntimeError('Unable to iterate cursor with no id');
    }

    const collection = this.ns.collection;
    if (collection == null) {
      // Cursors should have adopted the namespace returned by MongoDB
      // which should always defined a collection name (even a pseudo one, ex. db.aggregate())
      throw new MongoRuntimeError('A collection name must be determined before getMore');
    }

    const getMoreCmd: GetMoreCommand = {
      getMore: this.cursorId,
      collection
    };

    if (typeof this.options.batchSize === 'number') {
      getMoreCmd.batchSize = Math.abs(this.options.batchSize);
    }

View on GitHub (pinned to dce7939f86)