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 aggregateOptions
What it means
Thrown by AggregationCursor._initialize() (MongoAPIError) when explain is present in aggregateOptions and the explain/timeout option combination is invalid — specifically when validateExplainTimeoutOptions() detects timeoutMS used together with maxTimeMS (or explain.maxTimeMS). The driver forbids combining the modern timeoutMS with the legacy maxTimeMS on an explained aggregate command.
Source
Thrown at src/cursor/aggregation_cursor.ts:84
}
override map<T>(transform: (doc: TSchema) => T): AggregationCursor<T> {
return super.map(transform) as AggregationCursor<T>;
}
/** @internal */
async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
const options = {
...this.aggregateOptions,
...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 aggregateOptions'
);
}
}
const aggregateOperation = new AggregateOperation(this.namespace, this.pipeline, options);
const response = await executeOperation(this.client, aggregateOperation, this.timeoutContext);
return { server: aggregateOperation.server, session, response };
}
/** Execute the explain for the cursor */
async explain(): Promise<Document>;
async explain(verbosity: ExplainVerbosityLike | ExplainCommandOptions): Promise<Document>;
async explain(options: { timeoutMS?: number }): Promise<Document>;
async explain(
verbosity: ExplainVerbosityLike | ExplainCommandOptions,View on GitHub (pinned to 3366c21a63)
Solutions
- Use EITHER timeoutMS OR maxTimeMS, not both, on explained aggregations
- Drop maxTimeMS/explain.maxTimeMS from the options when using timeoutMS
- Call cursor.explain() instead of putting explain in aggregateOptions — explain() manages timeout separately
Example fix
// before
coll.aggregate(p, { explain: true, timeoutMS: 1000, maxTimeMS: 500 });
// after
coll.aggregate(p, { explain: true, maxTimeMS: 500 }); // or just timeoutMS 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.aggregate(p, 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 aggregations
- Prefer cursor.explain() over putting explain in aggregateOptions
- Sanitize shared options objects before passing to explained queries
When it happens
Trigger: collection.aggregate(pipeline, { explain: true, timeoutMS: N, maxTimeMS: M }) or explain.maxTimeMS set. Triggered lazily when the cursor initializes (first next()/toArray()).
Common situations: Migrating from maxTimeMS to timeoutMS while leaving explain/maxTimeMS in a shared options object; passing a generic query-options preset to both explained and non-explained queries.
Related errors
- timeoutMS cannot be used with explain when explain is specif
- Cannot use $out or $merge stage with ITERATION timeoutMode
- Server reported a timeout error
- Cannot use maxTimeMS with timeoutMS for explain commands.
- A change stream document has been received that lacks a resu
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/c78c41f26535b713.json.
Report an issue: GitHub.