mongodb/node-mongodb-native · error · MongoAPIError
timeoutMS cannot be used with explain when explain is specif
Error message
timeoutMS cannot be used with explain when explain is specified in findOptions
What it means
Thrown by FindCursor._initialize() (MongoAPIError) when explain is set in findOptions and validateExplainTimeoutOptions() rejects the option mix — i.e. timeoutMS combined with maxTimeMS (or explain.maxTimeMS) on an explained find. Mirrors the aggregation explain-timeout rule.
Source
Thrown at src/cursor/find_cursor.ts:84
override map<T>(transform: (doc: TSchema) => T): FindCursor<T> {
return super.map(transform) as FindCursor<T>;
}
/** @internal */
async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
const options = {
...this.findOptions, // NOTE: order matters here, we may need to refine this
...this.cursorOptions,
session,
signal: this.signal
};
if (options.explain) {
try {
validateExplainTimeoutOptions(options, Explain.fromOptions(options));
} catch {
throw new MongoAPIError(
'timeoutMS cannot be used with explain when explain is specified in findOptions'
);
}
}
const findOperation = new FindOperation(this.namespace, this.cursorFilter, options);
const response = await executeOperation(this.client, findOperation, this.timeoutContext);
// the response is not a cursor when `explain` is enabled
this.numReturned = response.batchSize;
return { server: findOperation.server, session, response };
}
/** @internal */
override async getMore(): Promise<CursorResponse> {
const numReturned = this.numReturned;View on GitHub (pinned to 3366c21a63)
Solutions
- Pick one timeout mechanism: use timeoutMS alone, or maxTimeMS alone
- Remove explain from findOptions and call cursor.explain() which handles timeouts
- Strip maxTimeMS/explain.maxTimeMS before constructing the cursor when using timeoutMS
Example fix
// before
coll.find({}, { explain: true, timeoutMS: 1000, maxTimeMS: 500 });
// after
coll.find({}, { explain: true, maxTimeMS: 500 }); Defensive patterns
Strategy: validation
Validate before calling
function cleanExplainTimeout(opts) {
if (opts.explain && opts.timeoutMS != null) {
const { maxTimeMS, explain, ...rest } = opts;
return { ...rest, explain: typeof explain === 'object' ? { ...explain, maxTimeMS: undefined } : explain };
}
return opts;
}
coll.find(filter, cleanExplainTimeout(opts)); Type guard
const hasConflictingTimeout = (o) => o.explain != null && o.timeoutMS != null && (o.maxTimeMS != null || o.explain?.maxTimeMS != null);
Prevention
- Use either timeoutMS or maxTimeMS, never both, on explained finds
- Prefer cursor.explain() over explain in findOptions
- Sanitize shared option presets before explained queries
When it happens
Trigger: collection.find(filter, { explain: true, timeoutMS: N, maxTimeMS: M }) or explain.maxTimeMS set. Fires when the cursor initializes on first iteration.
Common situations: Shared query-options presets mixing legacy maxTimeMS with new timeoutMS; explaining a query for debugging while a default timeout is globally applied.
Related errors
- timeoutMS cannot be used with explain when explain is specif
- Cannot use $out or $merge stage with ITERATION timeoutMode
- Argument for maxAwaitTimeMS must be a number
- Argument for maxTimeMS must be a number
- Cannot use maxTimeMS with timeoutMS for explain commands.
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/045d6db349ec898e.json.
Report an issue: GitHub.