mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Option "readPreference" must be a ReadPreference instance

Error message

Option "readPreference" must be a ReadPreference instance

What it means

Thrown by getReadPreference() when the readPreference option is neither a string nor a ReadPreference instance. The function accepts a ReadPreference instance or a string (which it converts via ReadPreference.fromString); anything else (number, object, null after coalescing) is invalid. Surfaced as MongoInvalidArgumentError. This is a direct user-facing validation of the readPreference option.

Source

Thrown at src/cmap/wire_protocol/shared.ts:23

import type { ServerDescription } from '../../sdam/server_description';
import type { Topology } from '../../sdam/topology';
import { TopologyDescription } from '../../sdam/topology_description';
import type { Connection } from '../connection';

export interface ReadPreferenceOption {
  readPreference?: ReadPreferenceLike;
}

export function getReadPreference(options?: ReadPreferenceOption): ReadPreference {
  // Default to command version of the readPreference.
  let readPreference = options?.readPreference ?? ReadPreference.primary;

  if (typeof readPreference === 'string') {
    readPreference = ReadPreference.fromString(readPreference);
  }

  if (!(readPreference instanceof ReadPreference)) {
    throw new MongoInvalidArgumentError(
      'Option "readPreference" must be a ReadPreference instance'
    );
  }

  return readPreference;
}

export function isSharded(topologyOrServer?: Topology | Server | Connection): boolean {
  if (topologyOrServer == null) {
    return false;
  }

  if (topologyOrServer.description && topologyOrServer.description.type === ServerType.Mongos) {
    return true;
  }

  // NOTE: This is incredibly inefficient, and should be removed once command construction
  // happens based on `Server` not `Topology`.

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Pass readPreference as a string: 'primary' | 'primaryPreferred' | 'secondary' | 'secondaryPreferred' | 'nearest'.
  2. Or construct a ReadPreference instance: ReadPreference.fromString('secondary') or new ReadPreference('secondary', tags).
  3. Avoid plain objects like { mode: 'secondary' }; the driver does not accept them.

Example fix

// before - plain object is not accepted
collection.find({}, { readPreference: { mode: 'secondary' } });

// after - use a string or a ReadPreference instance
import { ReadPreference } from 'mongodb';
collection.find({}, { readPreference: 'secondary' });
// or with tags
collection.find({}, { readPreference: new ReadPreference('secondary', [{ region: 'us-east' }]) });
Defensive patterns

Strategy: type-guard

Validate before calling

import { ReadPreference } from 'mongodb';
const VALID_MODES = new Set(['primary','primaryPreferred','secondary','secondaryPreferred','nearest']);
function normalizeReadPreference(rp) {
  if (typeof rp === 'string') { if (!VALID_MODES.has(rp)) throw new Error(`Invalid readPreference string: ${rp}`); return rp; }
  if (rp instanceof ReadPreference) return rp;
  throw new Error('readPreference must be a string or ReadPreference instance');
}
// usage
collection.find({}, { readPreference: normalizeReadPreference(options.readPreference) });

Type guard

import { ReadPreference } from 'mongodb';
function isReadPreferenceLike(rp): rp is string | ReadPreference {
  return typeof rp === 'string' || rp instanceof ReadPreference;
}
// usage
if (!isReadPreferenceLike(opts.readPreference)) throw new TypeError('Invalid readPreference');

Try / catch

try {
  await collection.find({}, { readPreference }).toArray();
} catch (err) {
  if (err instanceof MongoInvalidArgumentError && /readPreference" must be a ReadPreference instance/.test(err.message)) {
    // pass a string ('secondary') or a ReadPreference instance instead of a plain object
  }
  throw err;
}

Prevention

When it happens

Trigger: An operation or MongoClient is given options.readPreference set to an invalid value such as an object that is not a ReadPreference instance, a number, or a malformed value. Passing { mode: 'secondary' } (a plain object) instead of a ReadPreference instance or the string 'secondary' triggers it.

Common situations: Passing a plain object { mode, tags } instead of ReadPreference.construct(). Passing a typo or wrong-type value (e.g. a number). Library/framework that forwards a non-normalized readPreference into a driver call.

Related errors


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