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

Under Client-Side Operation Timeout (CSOT, the timeoutMS option) combining maxTimeMS with timeoutMS on explain commands is ambiguous and explicitly forbidden by validateExplainTimeoutOptions(). Pick a single timeout mechanism for explain.

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 3366c21a63)

Solutions

  1. Remove maxTimeMS from the explain options and rely on timeoutMS alone
  2. Or remove timeoutMS for this operation and keep maxTimeMS
  3. Standardize the project on timeoutMS and audit for leftover maxTimeMS

Example fix

// before
collection.find(f, { explain: { verbosity: 'queryPlanner', maxTimeMS: 1000 }, timeoutMS: 5000 });
// after
collection.find(f, { explain: { verbosity: 'queryPlanner' }, timeoutMS: 5000 });
Defensive patterns

Strategy: validation

Validate before calling

function assertExplainTimeout(options) {
  const hasMaxTime = options?.explain && typeof options.explain === 'object'
    && options.explain.maxTimeMS != null;
  if (options?.timeoutMS != null && (options?.maxTimeMS != null || hasMaxTime)) {
    throw new Error('Pick either maxTimeMS or timeoutMS for explain, not both');
  }
}

Prevention

When it happens

Trigger: collection.find(filter, { explain: { verbosity: 'queryPlanner', maxTimeMS: 1000 }, timeoutMS: 5000 }), or setting maxTimeMS on the command while timeoutMS is configured on the client/cursor.

Common situations: Migrating to CSOT while leaving legacy maxTimeMS in place; copy-pasting explain options into a timeoutMS-enabled codebase.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/da85d8bb7f9692a5.json. Report an issue: GitHub.