mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Option "maxStalenessSeconds" must be at least

Error message

Option "maxStalenessSeconds" must be at least ${maxStalenessVariance} seconds

What it means

Thrown by maxStalenessReducer() (src/sdam/server_selection.ts:132) as MongoInvalidArgumentError when maxStalenessSeconds is below the dynamic staleness variance floor, computed as (heartbeatFrequencyMS + IDLE_WRITE_PERIOD) / 1000. This floor accounts for clock skew and heartbeat latency per the max-staleness spec. The threshold varies with the topology's heartbeat frequency.

Solutions

  1. Increase maxStalenessSeconds to at least the value in the error message (the computed variance floor).
  2. Use the absolute minimum of 90 seconds (see error 336) as a safe default.
  3. If heartbeatFrequencyMS is high, lower it to reduce the variance floor.

Example fix

// before
new ReadPreference('secondary', undefined, { maxStalenessSeconds: 30 });
// after
new ReadPreference('secondary', undefined, { maxStalenessSeconds: 90 });
Defensive patterns

Strategy: validation

Validate before calling

const IDLE_WRITE_PERIOD = 10;
function safeMaxStaleness(v, heartbeatFrequencyMS = 10000) {
  const variance = (heartbeatFrequencyMS / 1000) + IDLE_WRITE_PERIOD;
  if (v < variance) throw new Error(`maxStalenessSeconds must be >= ${variance}`);
  return v;
}

Type guard

function isAboveVariance(v, heartbeatFrequencyMS = 10000): v is number {
  return typeof v === 'number' && v >= ((heartbeatFrequencyMS / 1000) + 10);
}

Try / catch

try {
  await collection.findOne({}, { readPreference: new ReadPreference('secondary', undefined, { maxStalenessSeconds }) });
} catch (e) {
  if (e instanceof MongoInvalidArgumentError && /maxStalenessSeconds/.test(e.message)) {
    // bump staleness and retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting maxStalenessSeconds to a small value (e.g. 10-30s) that is below the per-topology variance floor (~heartbeatFrequencyMS/1000 + 10s).

Common situations: Aggressive latency requirements leading developers to set very small staleness windows without accounting for heartbeat overhead.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/88b48331da9ca49e. Report an issue: GitHub.

Appendix: source

Thrown at src/sdam/server_selection.ts:132

 * @param readPreference - The read preference providing max staleness guidance
 * @param topologyDescription - The topology description
 * @param servers - The list of server descriptions to be reduced
 * @returns The list of servers that satisfy the requirements of max staleness
 */
function maxStalenessReducer(
  readPreference: ReadPreference,
  topologyDescription: TopologyDescription,
  servers: ServerDescription[]
): ServerDescription[] {
  if (readPreference.maxStalenessSeconds == null || readPreference.maxStalenessSeconds < 0) {
    return servers;
  }

  const maxStaleness = readPreference.maxStalenessSeconds;
  const maxStalenessVariance =
    (topologyDescription.heartbeatFrequencyMS + IDLE_WRITE_PERIOD) / 1000;
  if (maxStaleness < maxStalenessVariance) {
    throw new MongoInvalidArgumentError(
      `Option "maxStalenessSeconds" must be at least ${maxStalenessVariance} seconds`
    );
  }

  if (maxStaleness < SMALLEST_MAX_STALENESS_SECONDS) {
    throw new MongoInvalidArgumentError(
      `Option "maxStalenessSeconds" must be at least ${SMALLEST_MAX_STALENESS_SECONDS} seconds`
    );
  }

  if (topologyDescription.type === TopologyType.ReplicaSetWithPrimary) {
    const primary: ServerDescription = Array.from(topologyDescription.servers.values()).filter(
      primaryFilter
    )[0];

    return servers.filter((server: ServerDescription) => {
      const stalenessMS =
        server.lastUpdateTime -

View on GitHub (pinned to dce7939f86)