mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable aw
Error message
Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable awaitData cursor
What it means
Thrown during cursor construction when the cursor is tailable with awaitData, has a timeoutMS set, and maxAwaitTimeMS is greater than or equal to timeoutMS. For iteration-timeout tailable cursors, maxAwaitTimeMS must be strictly less than timeoutMS so the await window fits inside the per-iteration budget.
Source
Thrown at src/cursor/abstract_cursor.ts:291
? options.readPreference
: ReadPreference.primary,
...pluckBSONSerializeOptions(options),
timeoutMS: options?.timeoutContext?.csotEnabled()
? options.timeoutContext.timeoutMS
: options.timeoutMS,
tailable: options.tailable,
awaitData: options.awaitData
};
if (this.cursorOptions.timeoutMS != null) {
if (options.timeoutMode == null) {
if (options.tailable) {
if (options.awaitData) {
if (
options.maxAwaitTimeMS != null &&
options.maxAwaitTimeMS >= this.cursorOptions.timeoutMS
)
throw new MongoInvalidArgumentError(
'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)View on GitHub (pinned to 3366c21a63)
Solutions
- Make maxAwaitTimeMS strictly less than timeoutMS (e.g. timeoutMS=1000, maxAwaitTimeMS=500).
- Drop maxAwaitTimeMS and let the driver derive it from timeoutMS.
- If you want a single lifetime budget, remove tailable/awaitData so LIFETIME mode applies.
Example fix
// before
collection.find(filter, { tailable: true, awaitData: true, timeoutMS: 1000, maxAwaitTimeMS: 1000 });
// after
collection.find(filter, { tailable: true, awaitData: true, timeoutMS: 1000, maxAwaitTimeMS: 500 }); Defensive patterns
Strategy: validation
Validate before calling
function checkTailableTimeouts(opts) {
if (opts.tailable && opts.awaitData && opts.timeoutMS != null && opts.maxAwaitTimeMS != null) {
return opts.maxAwaitTimeMS < opts.timeoutMS;
}
return true;
} Prevention
- For tailable+awaitData cursors, keep maxAwaitTimeMS strictly below timeoutMS.
- Prefer setting only timeoutMS and let the driver derive maxAwaitTimeMS.
- Unit-test option builders that target capped-collection tailing.
When it happens
Trigger: Calling collection.find({}, { tailable: true, awaitData: true, timeoutMS: 1000, maxAwaitTimeMS: 1000 }) or any combination where maxAwaitTimeMS >= timeoutMS on a tailable+awaitData cursor (typical for change-stream-like polling on capped collections).
Common situations: Tuning change-stream tailing latency and setting both timeouts to the same value; migrating a legacy maxAwaitTimeMS config and adding timeoutMS for CSOT without adjusting the former.
Related errors
- Cannot set tailable cursor's timeoutMode to LIFETIME
- Cannot set timeoutMode without setting timeoutMS
- Argument for maxTimeMS must be a number
- Tailable cursor does not support batchSize
- Cannot rewind cursor that does not own its timeout context.
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/d1fb15dd70aff16c.json.
Report an issue: GitHub.