mongodb/node-mongodb-native · error · MongoTransactionError
Read preference in a transaction must be primary, not: ${rea
Error message
Read preference in a transaction must be primary, not: ${readPreference.mode} What it means
executeOperation (src/operations/execute_operation.ts:110) throws a MongoTransactionError when an operation is executed inside an active transaction but has a non-primary read preference. The MongoDB transaction specification requires all operations within a transaction to target the primary, so the driver rejects any secondary/nearest/etc. read preference up front.
Source
Thrown at src/operations/execute_operation.ts:110
) {
throw new MongoCompatibilityError('Snapshot reads require MongoDB 5.0 or later');
} else if (session.client !== client) {
throw new MongoInvalidArgumentError('ClientSession must be from the same MongoClient');
}
operation.session ??= session;
const readPreference = operation.readPreference ?? ReadPreference.primary;
const inTransaction = !!session?.inTransaction();
const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION);
if (
inTransaction &&
!readPreference.equals(ReadPreference.primary) &&
(hasReadAspect || operation.commandName === 'runCommand')
) {
throw new MongoTransactionError(
`Read preference in a transaction must be primary, not: ${readPreference.mode}`
);
}
if (session?.isPinned && session.transaction.isCommitted && !operation.bypassPinningCheck) {
session.unpin();
}
timeoutContext ??= TimeoutContext.create({
session,
serverSelectionTimeoutMS: client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: client.s.options.waitQueueTimeoutMS,
timeoutMS: operation.options.timeoutMS
});
try {
return await executeOperationWithRetries(operation, {
topology,View on GitHub (pinned to 3366c21a63)
Solutions
- Inside a transaction, do not set a non-primary read preference — the default primary is correct.
- If readPreference was set at the collection or db level, override it on the operation or use a separate client/collection without the preference for transactional work.
- Move secondary reads outside the transaction boundary.
Example fix
// before
const coll = db.collection('x', { readPreference: 'secondary' });
await session.withTransaction(async () => {
await coll.find({}).toArray(); // throws
});
// after
const coll = db.collection('x'); // no secondary preference for transactional access
await session.withTransaction(async () => {
await coll.find({}).toArray();
}); Defensive patterns
Strategy: validation
Validate before calling
import { ReadPreference } from 'mongodb';
function safeReadPreferenceForTransaction(
rp: ReadPreference | undefined,
inTransaction: boolean
): ReadPreference {
return inTransaction ? ReadPreference.primary : (rp ?? ReadPreference.primary);
} Try / catch
try {
await collection.find({}, { readPreference }).toArray();
} catch (err) {
if (err instanceof MongoTransactionError && /Read preference/.test(err.message)) {
// re-run with primary read preference
await collection.find({}).toArray();
} else throw err;
} Prevention
- Do not set non-primary read preferences at client/db/collection level if transactions are used.
- Inside withTransaction, always target primary.
- Keep analytical secondary reads outside transaction boundaries.
When it happens
Trigger: Calling collection.find(filter, { readPreference: 'secondary' }) (or setting readPreference on the collection/db/client level) while a session transaction is active, i.e. session.inTransaction() is true.
Common situations: Setting a global readPreference on the MongoClient for analytics workloads, then using the same client inside a transaction without overriding the preference. Also triggered by runCommand inside a transaction with a non-primary mode.
Related errors
- Option "readPreference" must be a ReadPreference instance
- Cannot have undefined values in key value pairs
- Cannot make read preference from ${JSON.stringify(value)}
- Unknown ReadPreference value: ${value}
- Invalid read preference: ${readPreference}
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/5fc283c5ed2433ee.json.
Report an issue: GitHub.