mongodb/node-mongodb-native · error · MongoRuntimeError

Cursor must be constructed with MongoClient

Error message

Cursor must be constructed with MongoClient

What it means

Thrown as a MongoRuntimeError in the AbstractCursor constructor when the first argument fails the `client.s.isMongoClient` check. Every cursor is bound to a MongoClient so it can run server selection, check out connections, track itself in `client.s.activeCursors`, and be cleaned up by MongoClient.close(). Passing anything else (a Db, Collection, plain object, or a mock) leaves the cursor without the runtime state it needs, so construction aborts. This is a programmer/internal error, not a transient runtime condition.

Solutions

  1. Always obtain cursors from a MongoClient-backed Collection/Db (e.g. collection.find(), db.aggregate()) instead of constructing them directly.
  2. If you must subclass a cursor, forward the exact MongoClient reference received from the parent cursor's `client` getter into super().
  3. In tests, use a real MongoClient connected to a test deployment or the driver's documented test harness rather than a hand-rolled mock that lacks `client.s.isMongoClient`.
  4. If you need to assert on the client type, check `client?.s?.isMongoClient === true` before constructing the cursor.

Example fix

// before (broken): passing a Db instead of the MongoClient
const cursor = new FindCursor(db, ns, options);

// after: use the Collection API, which forwards the client internally
const cursor = collection.find({}, options);
// or, when subclassing:
class MyCursor extends FindCursor {
  constructor(client: MongoClient, ns: MongoDBNamespace, options: FindOptions) {
    super(client, ns, options); // client must satisfy client.s.isMongoClient
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the client is a real MongoClient before building/subclassing a cursor
function isMongoClient(v: unknown): v is MongoClient {
  return !!v && typeof v === 'object' && (v as any)?.s?.isMongoClient === true;
}

if (!isMongoClient(client)) {
  throw new TypeError('A MongoClient is required to construct a cursor');;
}

Type guard

import type { MongoClient } from 'mongodb';
function isMongoClient(v: unknown): v is MongoClient {
  return !!v && typeof v === 'object' && (v as any)?.s?.isMongoClient === true;
}

Prevention

When it happens

Trigger: Constructing an AbstractCursor subclass (e.g. FindCursor, AggregationCursor) directly with a non-MongoClient first argument, or with an object whose `s.isMongoClient` flag is missing/false. In practice this fires when library/extension code subclasses a cursor and forgets to forward the client, or when test code passes a stub instead of a real MongoClient.

Common situations: Writing a custom cursor subclass that calls super() with a Db or Collection instead of the underlying client; mocking the driver with an object that omits the internal `s` state; migrating code that hand-constructed cursors in an older driver version.

Related errors


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

Appendix: source

Thrown at src/cursor/abstract_cursor.ts:262

  /** @event */
  static readonly CLOSE = 'close' as const;

  /** @internal */
  protected deserializationOptions: OnDemandDocumentDeserializeOptions;
  protected signal: AbortSignal | undefined;
  private abortListener: Disposable | undefined;

  /** @internal */
  protected constructor(
    client: MongoClient,
    namespace: MongoDBNamespace,
    options: AbstractCursorOptions & Abortable = {}
  ) {
    super();
    this.on('error', noop);

    if (!client.s.isMongoClient) {
      throw new MongoRuntimeError('Cursor must be constructed with MongoClient');
    }
    this.cursorClient = client;
    this.cursorNamespace = namespace;
    this.cursorId = null;
    this.initialized = false;
    this.isClosed = false;
    this.isKilled = false;
    this.cursorOptions = {
      readPreference:
        options.readPreference && options.readPreference instanceof ReadPreference
          ? options.readPreference
          : ReadPreference.primary,
      ...pluckBSONSerializeOptions(options),
      timeoutMS: options?.timeoutContext?.csotEnabled()
        ? options.timeoutContext.timeoutMS
        : options.timeoutMS,
      tailable: options.tailable,
      awaitData: options.awaitData

View on GitHub (pinned to dce7939f86)