mongodb/node-mongodb-native · error · MongoAPIError
Cannot use maxTimeMS with timeoutMS for explain commands.
Error message
Cannot use maxTimeMS with timeoutMS for explain commands.
What it means
The driver's Client-Side Operation Timeout (CSOT) model treats timeoutMS as the overarching budget. For explain commands, specifying both maxTimeMS and timeoutMS is contradictory, so validateExplainTimeoutOptions (src/explain.ts:93) throws a MongoAPIError. This prevents two competing timeout semantics from being sent in the same command.
Solutions
- Remove maxTimeMS (both top-level and inside the explain option) when timeoutMS is set.
- Or remove timeoutMS for this call and rely solely on maxTimeMS.
- Avoid setting a global timeoutMS if you need per-command maxTimeMS control on explain queries.
Example fix
// before
await coll.find({}, { explain: { verbosity: 'queryPlanner', maxTimeMS: 1000 }, timeoutMS: 5000 }).toArray();
// after
await coll.find({}, { explain: { verbosity: 'queryPlanner' }, timeoutMS: 5000 }).toArray(); Defensive patterns
Strategy: validation
Validate before calling
function reconcileTimeoutOptions(options) {
if (options?.timeoutMS != null) {
delete options.maxTimeMS;
if (options.explain && typeof options.explain === 'object') delete options.explain.maxTimeMS;
}
return options;
} Type guard
function hasConflictingTimeouts(options: any): boolean {
return options?.timeoutMS != null && (options?.maxTimeMS != null || options?.explain?.maxTimeMS != null);
} Try / catch
try {
await coll.find({}, opts).explain();
} catch (e) {
if (e instanceof MongoAPIError && /maxTimeMS with timeoutMS/.test(e.message)) {
// remove maxTimeMS and retry
}
throw e;
} Prevention
- Adopt a single timeout strategy per command: either timeoutMS (CSOT) or maxTimeMS, not both.
- When setting a global timeoutMS, audit explain paths for per-call maxTimeMS.
- Encapsulate timeout option resolution in one helper.
When it happens
Trigger: Calling collection.find(..., { explain: { verbosity, maxTimeMS }, maxTimeMS, timeoutMS }) or aggregation explain with both maxTimeMS (either top-level or nested in explain) and timeoutMS set. Combining a globally configured timeoutMS with a per-call maxTimeMS on an explained command.
Common situations: Setting timeoutMS on the MongoClient and then passing maxTimeMS to a specific explain() call. Migrating from maxTimeMS to CSOT timeoutMS without removing the old maxTimeMS on explained queries.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- An operation cannot be given a timeoutMS setting when…
- Cannot create a Timeout with a negative duration
- Cannot set timeoutMode without setting timeoutMS
- Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable…
- Expired after ms
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/da85d8bb7f9692a5.
Report an issue: GitHub.
Appendix: source
Thrown at src/explain.ts:96
this.maxTimeMS = maxTimeMS;
}
static fromOptions({ explain }: ExplainOptions = {}): Explain | undefined {
if (explain == null) return;
if (typeof explain === 'boolean' || typeof explain === 'string') {
return new Explain(explain);
}
const { verbosity, maxTimeMS } = explain;
return new Explain(verbosity, maxTimeMS);
}
}
export function validateExplainTimeoutOptions(options: Document, explain?: Explain) {
const { maxTimeMS, timeoutMS } = options;
if (timeoutMS != null && (maxTimeMS != null || explain?.maxTimeMS != null)) {
throw new MongoAPIError('Cannot use maxTimeMS with timeoutMS for explain commands.');
}
}
/**
* Applies an explain to a given command.
* @internal
*
* @param command - the command on which to apply the explain
* @param options - the options containing the explain verbosity
*/
export function decorateWithExplain(
command: Document,
explain: Explain
): {
explain: Document;
verbosity: ExplainVerbosity;
maxTimeMS?: number;
} {View on GitHub (pinned to dce7939f86)