mongodb/node-mongodb-native · error · MongoAPIError
Cannot rewind cursor that does not own its timeout context.
Error message
Cannot rewind cursor that does not own its timeout context.
What it means
MongoAPIError thrown by cursor.rewind() when a timeoutContext exists but its owner is not this cursor. Cursors that share/borrow a CSOT timeout context (e.g. derived cursors, change streams with an explicit timeout context passed from a session) cannot rewind because resetting the timer would affect the owning context.
Source
Thrown at src/cursor/abstract_cursor.ts:822
throw new MongoTailableCursorError('Tailable cursor does not support batchSize');
}
if (typeof value !== 'number') {
throw new MongoInvalidArgumentError('Operation "batchSize" requires an integer');
}
this.cursorOptions.batchSize = value;
return this;
}
/**
* Rewind this cursor to its uninitialized state. Any options that are present on the cursor will
* remain in effect. Iterating this cursor will cause new queries to be sent to the server, even
* if the resultant data has already been retrieved by this cursor.
*/
rewind(): void {
if (this.timeoutContext && this.timeoutContext.owner !== this) {
throw new MongoAPIError(`Cannot rewind cursor that does not own its timeout context.`);
}
if (!this.initialized) {
return;
}
this.cursorId = null;
this.documents?.clear();
this.timeoutContext?.clear();
this.timeoutContext = undefined;
this.isClosed = false;
this.isKilled = false;
this.initialized = false;
this.hasEmittedClose = false;
this.trackCursor();
// We only want to end this session if we created it, and it hasn't ended yet
if (this.cursorSession?.explicit === false) {
if (!this.cursorSession.hasEnded) {View on GitHub (pinned to 3366c21a63)
Solutions
- Do not call rewind() on cursors whose timeoutContext is externally owned — construct a new cursor instead.
- If you need re-iteration, clone the cursor before iterating so the clone can be re-run.
- Drop the shared timeoutContext before rewinding, or own the context by passing timeoutMS at cursor level.
Example fix
// before cursor.rewind(); // cursor's timeoutContext owned by session // after const fresh = collection.find(filter); // new cursor with its own context
Defensive patterns
Strategy: try-catch
Validate before calling
if (cursor.timeoutContext && cursor.timeoutContext.owner !== cursor) throw new Error('cannot rewind borrowed timeout context'); Try / catch
try {
cursor.rewind();
} catch (e) {
if (e.name === 'MongoAPIError' && /does not own its timeout context/.test(e.message)) {
// build a fresh cursor instead
cursor = collection.find(filter);
} else throw e;
} Prevention
- Avoid rewind() on cursors derived from a session-level or borrowed CSOT context.
- Build a fresh cursor (or clone) to re-run a query when the timeout is externally owned.
- Pass timeoutMS at the cursor level so it owns its own context if you need rewind.
When it happens
Trigger: Calling rewind() on a cursor constructed with an externally-supplied timeoutContext (timeoutContext.owner !== this), such as a cloned cursor or one bound to a session-level CSOT context. The guard `this.timeoutContext.owner !== this` catches this ownership mismatch.
Common situations: Using CSOT with sessions and then attempting rewind on a cursor whose timeout came from the operation/session; cloning cursors that carry a shared timeout context; calling rewind in a retry loop with borrowed contexts.
Related errors
- Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable aw
- Cannot set tailable cursor's timeoutMode to LIFETIME
- Cannot set timeoutMode without setting timeoutMS
- Use of expired sessions is not permitted
- KMS request timed out
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/b4d94998d03ecd6b.json.
Report an issue: GitHub.