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 an instance of ReadPreference. After attempting string->instance conversion, the function asserts instanceof ReadPreference and raises a MongoInvalidArgumentError if it fails. This is a client-side argument validation error, fully under the caller's control.
Solutions
- Pass a valid string mode: 'primary' | 'primaryPreferred' | 'secondary' | 'secondaryPreferred' | 'nearest'.
- Or construct a ReadPreference instance: new ReadPreference('secondary').
- If loading config from JSON, coerce to string before passing.
- Check for typos and stray wrapping objects in the option.
Example fix
// before
collection.find({}, { readPreference: { mode: 'secondary' } });
// after
collection.find({}, { readPreference: 'secondary' }); Defensive patterns
Strategy: type-guard
Validate before calling
const RP_MODES = ['primary','primaryPreferred','secondary','secondaryPreferred','nearest'] as const;
function asReadPreference(v: unknown) {
if (typeof v === 'string' && (RP_MODES as readonly string[]).includes(v)) return v;
if (v instanceof ReadPreference) return v;
throw new TypeError(`Invalid readPreference: ${String(v)}`);
} Type guard
import { ReadPreference } from 'mongodb';
function isValidReadPreference(v: unknown): v is string | ReadPreference {
if (v instanceof ReadPreference) return true;
if (typeof v === 'string') {
return ['primary','primaryPreferred','secondary','secondaryPreferred','nearest'].includes(v);
}
return false;
} Prevention
- Pass readPreference as a string mode or a ReadPreference instance only.
- Coerce config loaded from JSON/env to a string before passing.
- Type the option field so TypeScript rejects plain objects.
When it happens
Trigger: Fires at src/cmap/wire_protocol/shared.ts:23 when options.readPreference is a non-string, non-ReadPreference value (e.g. a plain object like {mode:'secondary'} or a number). Triggered on any read operation (find, aggregate, count, listDatabases) or when setting collection/db-level read preferences.
Common situations: Passing {mode: 'secondary'} instead of 'secondary' or new ReadPreference('secondary'); passing a string the driver cannot parse (e.g. 'SECONDARY' works but typos do not); migrating code that built read preference objects manually; spreading untyped config from env/JSON without coercion.
Related errors
- Argument "docs" must be an array of documents
- Argument "operations" must be an array of documents
- Argument "pipeline" must be an array of aggregation stages
- Auth mechanism property ALLOWED_HOSTS must be an array of…
- Cannot create a Timeout with a negative duration
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/8ea69d14e72e7000.
Report an issue: GitHub.
Appendix: 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 dce7939f86)