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
- Set all options before the first await on the cursor (chain .filter().sort().limit() first, then iterate)
- If you need a changed query, call cursor.clone() to get a fresh un-initialized copy and modify that
- 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
- Chain all builder methods before the first await/iteration
- Call clone() to get a fresh, modifiable copy of a used cursor
- Create a new find()/aggregate() rather than reusing a consumed cursor
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
- Cursor is exhausted
- Cannot rewind cursor that does not own its timeout context.
- Cursor returned a `null` document, but the cursor is not exh
- Unable to iterate cursor with no id
- This batch has already been executed, create new batch to ex
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/acc895fcdff9d4a5.json.
Report an issue: GitHub.