mongodb/node-mongodb-native · error · MongoRuntimeError

Unexpected null cursor id. A cursor creating command should

Error message

Unexpected null cursor id. A cursor creating command should have set this

What it means

Thrown by AbstractCursor.getMore() when the cursor's cursorId is null at the moment a getMore command is about to be dispatched. The cursorId is assigned during cursorInit() from the initial command response (abstract_cursor.ts:916); getMore() is only reached after fetchBatch() guards on cursorId == null and calls cursorInit() first. Seeing this error means the driver reached a state where initialization was skipped or failed to populate the id, which indicates an internal driver bug or a corrupted/monkey-patched cursor lifecycle.

Source

Thrown at src/cursor/abstract_cursor.ts:861

      this.cursorSession = null;
    }
  }

  /**
   * Returns a new uninitialized copy of this cursor, with options matching those that have been set on the current instance
   */
  abstract clone(): AbstractCursor<TSchema>;

  /** @internal */
  protected abstract _initialize(
    session: ClientSession | undefined
  ): Promise<InitialCursorResponse>;

  /** @internal */
  async getMore(): Promise<CursorResponse> {
    if (this.cursorId == null) {
      throw new MongoRuntimeError(
        'Unexpected null cursor id. A cursor creating command should have set this'
      );
    }
    if (this.selectedServer == null) {
      throw new MongoRuntimeError(
        'Unexpected null selectedServer. A cursor creating command should have set this'
      );
    }

    if (this.cursorSession == null) {
      throw new MongoRuntimeError(
        'Unexpected null session. A cursor creating command should have set this'
      );
    }
    const getMoreOptions = {
      ...this.cursorOptions,
      session: this.cursorSession,
      batchSize: this.cursorOptions.batchSize

View on GitHub (pinned to 3366c21a63)

Solutions

  1. If you subclass AbstractCursor, ensure _initialize() resolves an InitialCursorResponse whose response.id is a valid Long/number and never null
  2. Stop calling the @internal getMore() method directly; use the public next()/toArray()/forEach() iteration APIs which call cursorInit() first
  3. If you believe you hit this via normal API use, report a driver bug with a reproduction against the current mongodb package version

Example fix

// before (broken subclass)
class MyCursor extends AbstractCursor {
  async _initialize() {
    return { response: someResp, server, session }; // someResp.id is undefined
  }
}
// after
async _initialize() {
  const response = await executeOperation(this.client, op);
  if (response.id == null) throw new Error('init returned no cursor id');
  return { response, server: op.server, session };
}
Defensive patterns

Strategy: validation

Validate before calling

// Not user-reachable via public APIs; validate your subclass instead.
// If you subclass AbstractCursor, assert the init response:
async function safeInit(cursor) {
  const state = await cursor._initialize(undefined);
  if (state.response.id == null) throw new Error('init returned null cursor id');
  return state;
}

Prevention

When it happens

Trigger: Reached only if getMore() is called directly while cursorId is still null, bypassing the fetchBatch() guard at abstract_cursor.ts:948. Realistic triggers: a subclass overriding _initialize() to return a response with a null/undefined id, calling the internal getMore() via test helpers, or a partially-applied monkey patch on cursorInit that swallows the assignment.

Common situations: Custom AbstractCursor subclasses, test code reaching into @internal methods, or a driver downgrade/upgrade mismatch where a cursor subclass from an older version is used with a newer runtime.

Related errors


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