MongoDB error 20
Transaction numbers are only allowed on a replica set member or mongos
You started a transaction (or a retryable write) on a standalone mongod, and only replica sets and sharded clusters support them. Run the server as a replica set; a single-member set is enough for development.
Transaction numbers are only allowed on a replica set member or mongos
Tested on MongoDB 8.0.32 (mongosh 2.12.0; Node.js driver 6.18, 6.20 and 7.5) · Updated 9 October 2026
What it means
Transactions and retryable writes tag each operation with a session and a transaction number. Only
a replica set member or a mongos (the router of a sharded cluster) keeps the log that makes those
work. A standalone mongod refuses them with code 20, IllegalOperation, and this message.
Newer Node.js drivers show a different message for the same error. In our tests, the Node.js driver 7.5.0 replaced it, for writes, with:
This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.
Drivers 6.18.0 and 6.20.0 passed the server’s message through. The advice in that message doesn’t
help here: with retryWrites=false in the URL, the transaction failed the same way. A transaction
on a standalone server fails whatever the options.
Common causes
- A standalone server in development:
mongodstarted without--replSet, or the official Docker image run with its defaults, while the code usessession.startTransaction()orwithTransaction(). - A library that uses transactions for you. Some ORMs and frameworks wrap writes in transactions, so the error appears without a transaction in your own code.
- A connection straight to one member that isn’t part of a set, for example a test server restored from a production backup but started as a standalone.
How to fix it
Check what you’re connected to
db.hello().setName
A replica set name means a replica set; nothing (undefined) on a mongod means a standalone.
db.hello().msg is isdbgrid on a mongos.
Run a single-member replica set for development
Start mongod with a replica set name and initiate the set once. With Docker:
docker run -d --name mongo-rs -p 27017:27017 mongo:8.0 --replSet rs0 --bind_ip_all
docker exec mongo-rs mongosh --eval 'rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] })'
The member’s host must be a name your app can reach: here localhost:27017, because the app runs
on the same machine with the port published. If you can’t control that name, connect with
directConnection=true (see server selection errors).
Convert an existing standalone
Your data stays. Shut the server down, add the replica set name to its configuration, start it
and run rs.initiate():
replication:
replSetName: rs0
If the server has access control turned on, a replica set also needs internal authentication
between members, usually a key file (security.keyFile). Without one, mongod refuses to start
(shown below). Update your connection strings to include replicaSet=rs0, or list the members.
Use a deployment that already supports transactions
Replica sets and sharded clusters support transactions. Atlas clusters are replica sets (or sharded clusters), so the same code works there; see connecting to Atlas.
If you don’t need a transaction
A single-document write is already atomic in MongoDB. If you only needed to change one document, drop the session and transaction. Ordinary writes work on a standalone server without any change: drivers only attach transaction numbers to them when the server supports retryable writes.
Reproduce it
On the standalone test server (MongoDB 8.0.32), the raw command a driver sends inside a transaction, run in mongosh with the error caught and printed:
db.runCommand({
insert: "accounts", documents: [{ _id: "carol" }],
lsid: { id: UUID() }, txnNumber: NumberLong(1),
autocommit: false, startTransaction: true
})
{
name: 'MongoServerError',
code: 20,
codeName: 'IllegalOperation',
message: 'Transaction numbers are only allowed on a replica set member or mongos'
}
A retryable write (the same insert with txnNumber but no transaction) got the same error.
From a Node.js script on the Mac with driver 6.20.0 (and 6.18.0, also with withTransaction()):
const session = client.startSession()
session.startTransaction()
await client.db("seo_mongo").collection("accounts").insertOne({ _id: "manual" }, { session })
MongoServerError: Transaction numbers are only allowed on a replica set member or mongos
The same transaction through mongosh 2.12.0, which uses the Node.js driver 7.5.0:
MongoServerError: This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.
That error had no code. With retryWrites=false in the URL it was unchanged, and a findOne
inside the transaction got the server’s own message with code 20. A plain insertOne without a
session worked.
On a temporary single-member replica set (mongo:8.0 --replSet rs0, member localhost:37421,
port published to the Mac), the same script printed committed, with replicaSet=rs0 in the URL
and without it.
Starting mongod with both --replSet rs0 and --auth but no key file:
BadValue: security.keyFile is required when authorization is enabled with replica sets
In Inlet
Paste the same connection URL your app uses (with replicaSet=rs0 or directConnection=true if it
needs one) and Inlet fills the connection form. Collections show as tables and queries use mongosh
syntax, so you can check the data your transaction wrote.
Related
Sources
- www.mongodb.com/docs/manual/core/transactions/
- www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set/
- www.mongodb.com/docs/manual/core/retryable-writes/
- www.mongodb.com/docs/manual/reference/command/hello/
- www.mongodb.com/docs/manual/reference/connection-string-options/
- github.com/mongodb/node-mongodb-native/blob/main/src/operations/execute_operation.ts
- www.mongodb.com/docs/manual/reference/error-codes/
- www.mongodb.com/community/forums/t/is-there-any-way-to-use-transactions-with-m0-sandbox/7847