{"record":{"id":"a04ac77821734d00","repo":"mongodb/node-mongodb-native","slug":"cursor-must-be-constructed-with-mongoclient","errorCode":null,"errorMessage":"Cursor must be constructed with MongoClient","messagePattern":"Cursor must be constructed with MongoClient","errorType":"exception","errorClass":"MongoRuntimeError","httpStatus":null,"severity":"error","filePath":"src/cursor/abstract_cursor.ts","lineNumber":262,"sourceCode":"  /** @event */\n  static readonly CLOSE = 'close' as const;\n\n  /** @internal */\n  protected deserializationOptions: OnDemandDocumentDeserializeOptions;\n  protected signal: AbortSignal | undefined;\n  private abortListener: Disposable | undefined;\n\n  /** @internal */\n  protected constructor(\n    client: MongoClient,\n    namespace: MongoDBNamespace,\n    options: AbstractCursorOptions & Abortable = {}\n  ) {\n    super();\n    this.on('error', noop);\n\n    if (!client.s.isMongoClient) {\n      throw new MongoRuntimeError('Cursor must be constructed with MongoClient');\n    }\n    this.cursorClient = client;\n    this.cursorNamespace = namespace;\n    this.cursorId = null;\n    this.initialized = false;\n    this.isClosed = false;\n    this.isKilled = false;\n    this.cursorOptions = {\n      readPreference:\n        options.readPreference && options.readPreference instanceof ReadPreference\n          ? options.readPreference\n          : ReadPreference.primary,\n      ...pluckBSONSerializeOptions(options),\n      timeoutMS: options?.timeoutContext?.csotEnabled()\n        ? options.timeoutContext.timeoutMS\n        : options.timeoutMS,\n      tailable: options.tailable,\n      awaitData: options.awaitData","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/cursor/abstract_cursor.ts#L244-L280","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Always obtain cursors from a MongoClient-backed Collection/Db (e.g. collection.find(), db.aggregate()) instead of constructing them directly.","If you must subclass a cursor, forward the exact MongoClient reference received from the parent cursor's `client` getter into super().","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`.","If you need to assert on the client type, check `client?.s?.isMongoClient === true` before constructing the cursor."],"exampleFix":"// before (broken): passing a Db instead of the MongoClient\nconst cursor = new FindCursor(db, ns, options);\n\n// after: use the Collection API, which forwards the client internally\nconst cursor = collection.find({}, options);\n// or, when subclassing:\nclass MyCursor extends FindCursor {\n  constructor(client: MongoClient, ns: MongoDBNamespace, options: FindOptions) {\n    super(client, ns, options); // client must satisfy client.s.isMongoClient\n  }\n}","handlingStrategy":"validation","validationCode":"// Verify the client is a real MongoClient before building/subclassing a cursor\nfunction isMongoClient(v: unknown): v is MongoClient {\n  return !!v && typeof v === 'object' && (v as any)?.s?.isMongoClient === true;\n}\n\nif (!isMongoClient(client)) {\n  throw new TypeError('A MongoClient is required to construct a cursor');;\n}","typeGuard":"import type { MongoClient } from 'mongodb';\nfunction isMongoClient(v: unknown): v is MongoClient {\n  return !!v && typeof v === 'object' && (v as any)?.s?.isMongoClient === true;\n}","tryCatchPattern":null,"preventionTips":["Never construct cursors directly; always obtain them from Collection/Db methods.","When subclassing, forward the exact MongoClient from the parent cursor's `client` getter.","In tests, use a real MongoClient against a test deployment rather than a stub."],"tags":["cursor","constructor","mongo-client","internal-misuse","typescript"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}