{"id":"8ea69d14e72e7000","repo":"mongodb/node-mongodb-native","slug":"option-readpreference-must-be-a-readpreference-i","errorCode":null,"errorMessage":"Option \"readPreference\" must be a ReadPreference instance","messagePattern":"Option \"readPreference\" must be a ReadPreference instance","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/cmap/wire_protocol/shared.ts","lineNumber":23,"sourceCode":"import type { ServerDescription } from '../../sdam/server_description';\nimport type { Topology } from '../../sdam/topology';\nimport { TopologyDescription } from '../../sdam/topology_description';\nimport type { Connection } from '../connection';\n\nexport interface ReadPreferenceOption {\n  readPreference?: ReadPreferenceLike;\n}\n\nexport function getReadPreference(options?: ReadPreferenceOption): ReadPreference {\n  // Default to command version of the readPreference.\n  let readPreference = options?.readPreference ?? ReadPreference.primary;\n\n  if (typeof readPreference === 'string') {\n    readPreference = ReadPreference.fromString(readPreference);\n  }\n\n  if (!(readPreference instanceof ReadPreference)) {\n    throw new MongoInvalidArgumentError(\n      'Option \"readPreference\" must be a ReadPreference instance'\n    );\n  }\n\n  return readPreference;\n}\n\nexport function isSharded(topologyOrServer?: Topology | Server | Connection): boolean {\n  if (topologyOrServer == null) {\n    return false;\n  }\n\n  if (topologyOrServer.description && topologyOrServer.description.type === ServerType.Mongos) {\n    return true;\n  }\n\n  // NOTE: This is incredibly inefficient, and should be removed once command construction\n  // happens based on `Server` not `Topology`.","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cmap/wire_protocol/shared.ts#L5-L41","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass readPreference as a string: 'primary' | 'primaryPreferred' | 'secondary' | 'secondaryPreferred' | 'nearest'.","Or construct a ReadPreference instance: ReadPreference.fromString('secondary') or new ReadPreference('secondary', tags).","Avoid plain objects like { mode: 'secondary' }; the driver does not accept them."],"exampleFix":"// before - plain object is not accepted\ncollection.find({}, { readPreference: { mode: 'secondary' } });\n\n// after - use a string or a ReadPreference instance\nimport { ReadPreference } from 'mongodb';\ncollection.find({}, { readPreference: 'secondary' });\n// or with tags\ncollection.find({}, { readPreference: new ReadPreference('secondary', [{ region: 'us-east' }]) });","handlingStrategy":"type-guard","validationCode":"import { ReadPreference } from 'mongodb';\nconst VALID_MODES = new Set(['primary','primaryPreferred','secondary','secondaryPreferred','nearest']);\nfunction normalizeReadPreference(rp) {\n  if (typeof rp === 'string') { if (!VALID_MODES.has(rp)) throw new Error(`Invalid readPreference string: ${rp}`); return rp; }\n  if (rp instanceof ReadPreference) return rp;\n  throw new Error('readPreference must be a string or ReadPreference instance');\n}\n// usage\ncollection.find({}, { readPreference: normalizeReadPreference(options.readPreference) });","typeGuard":"import { ReadPreference } from 'mongodb';\nfunction isReadPreferenceLike(rp): rp is string | ReadPreference {\n  return typeof rp === 'string' || rp instanceof ReadPreference;\n}\n// usage\nif (!isReadPreferenceLike(opts.readPreference)) throw new TypeError('Invalid readPreference');","tryCatchPattern":"try {\n  await collection.find({}, { readPreference }).toArray();\n} catch (err) {\n  if (err instanceof MongoInvalidArgumentError && /readPreference\" must be a ReadPreference instance/.test(err.message)) {\n    // pass a string ('secondary') or a ReadPreference instance instead of a plain object\n  }\n  throw err;\n}","preventionTips":["Pass readPreference as one of the string modes or a ReadPreference instance.","Never pass a plain object { mode, tags }; construct ReadPreference instead.","Centralize readPreference normalization in a helper to avoid ad-hoc values."],"tags":["read-preference","configuration","validation","typescript"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}