mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Cannot set timeoutMode without setting timeoutMS
Error message
Cannot set timeoutMode without setting timeoutMS
What it means
Thrown as a MongoInvalidArgumentError in the AbstractCursor constructor when timeoutMode is supplied but timeoutMS is not. timeoutMode only describes how an existing timeoutMS deadline is applied (per-iteration vs whole-cursor), so it is meaningless without a deadline. The constructor explicitly checks `options.timeoutMode != null` only in the `else` branch where `timeoutMS` is absent, and rejects the pairing to prevent silent no-op configuration.
Solutions
- Always set timeoutMS whenever you set timeoutMode.
- If you do not want a timeout, remove both timeoutMS and timeoutMode.
- Centralize timeout config so timeoutMode is only assigned together with a finite timeoutMS.
Example fix
// before: timeoutMode with no deadline
const cursor = collection.find(filter, { timeoutMode: 'iteration' });
// after: provide the deadline the mode applies to
const cursor = collection.find(filter, { timeoutMS: 1000, timeoutMode: 'iteration' }); Defensive patterns
Strategy: validation
Validate before calling
if (opts.timeoutMode != null && opts.timeoutMS == null) {
throw new RangeError('timeoutMode requires timeoutMS to be set as well.');
} Prevention
- Always pair timeoutMode with a finite timeoutMS.
- If you do not want a timeout, omit both options.
- Type your options builder so timeoutMode can only be set through a helper that also sets timeoutMS.
When it happens
Trigger: collection.find(filter, { timeoutMode: 'iteration' }) with no timeoutMS; passing a shared options object that sets timeoutMode but whose timeoutMS was conditionally deleted/undefined.
Common situations: Refactoring timeout code and dropping the timeoutMS line while leaving timeoutMode; spreading a base options object that always includes timeoutMode but only sometimes includes timeoutMS.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Cannot set tailable cursor's timeoutMode to LIFETIME
- Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable…
- Cannot use $out or $merge stage with ITERATION timeoutMode
- An operation cannot be given a timeoutMS setting when…
- Argument for maxTimeMS must be a number
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/bed84e3365b5b59c.
Report an issue: GitHub.
Appendix: source
Thrown at src/cursor/abstract_cursor.ts:310
'Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable awaitData cursor'
);
}
this.cursorOptions.timeoutMode = CursorTimeoutMode.ITERATION;
} else {
this.cursorOptions.timeoutMode = CursorTimeoutMode.LIFETIME;
}
} else {
if (options.tailable && options.timeoutMode === CursorTimeoutMode.LIFETIME) {
throw new MongoInvalidArgumentError(
"Cannot set tailable cursor's timeoutMode to LIFETIME"
);
}
this.cursorOptions.timeoutMode = options.timeoutMode;
}
} else {
if (options.timeoutMode != null)
throw new MongoInvalidArgumentError('Cannot set timeoutMode without setting timeoutMS');
}
// Set for initial command
this.cursorOptions.omitMaxTimeMS =
this.cursorOptions.timeoutMS != null &&
((this.cursorOptions.timeoutMode === CursorTimeoutMode.ITERATION &&
!this.cursorOptions.tailable) ||
(this.cursorOptions.tailable && !this.cursorOptions.awaitData));
const readConcern = ReadConcern.fromOptions(options);
if (readConcern) {
this.cursorOptions.readConcern = readConcern;
}
if (typeof options.batchSize === 'number') {
this.cursorOptions.batchSize = options.batchSize;
}
View on GitHub (pinned to dce7939f86)