MongoServerError: not primary and secondaryOk=false

I have set up a MongoDB replica set with three nodes in my local environment. The replica set consists of one primary node and two secondary nodes. I’m using Node.js to connect to one of the secondary members in the replica set.

However, when I attempt to run the planCacheListFilters command on the secondary member, I encounter the following error:

Error:

MongoServerError: not primary and secondaryOk=false

This error suggests that the command is unable to run on a secondary node because it requires a primary node, and the secondaryOk option is set to false.

I would like to understand how to properly configure my MongoDB connection or the planCacheListFilters command to execute successfully on a secondary node. Additionally, if there are any specific considerations or permissions required for running this command on secondary members, I would appreciate guidance on that.

Code:

const { MongoClient } = require('mongodb');

// The MongoDB URI for the secondary member in the replica set
const uri = 'mongodb://ak:nomercy@localhost:27018/?authSource=admin&directConnection=true';
const client = new MongoClient(uri);

async function connect() {
  try {
    await client.connect();
    console.log('Connected to MongoDB');

    const db = client.db('ak');
    const { filters } = await db.command({ planCacheListFilters: 'test' });
    filters.forEach(function (plan) {
        console.log(plan);
    });
  } catch (err) {
    console.error('Error connecting to MongoDB:', err);
  } finally {
    await client.close();
  }
}

connect();

Version details:

Mongo version: 4.4.24
Node JS version: v20.5.1
Mongo driver version: 6.0.0

Do pass all 3 ReplicaSet Member uri in deployment string

const uri = ‘mongodb://ak:nomercy@localhost:27017,localhost:27018,localhost:27019/authSource=admin&directConnection=true’;

It will switch between primary and secondary nodes

Set the readPreference=secondary on the connection string.

2 Likes

I followed the solution you provided, but I encountered the following error:

/home/nomercy/project/NodeJS/node_modules/mongodb/lib/connection_string.js:358
        throw new error_1.MongoParseError('directConnection option requires exactly one host');
        ^

MongoParseError: directConnection option requires exactly one host
    at parseOptions (/home/nomercy/project/NodeJS/node_modules/mongodb/lib/connection_string.js:358:15)
    at new MongoClient (/home/nomercy/project/NodeJS/node_modules/mongodb/lib/mongo_client.js:51:63)
    at Object.<anonymous> (/home/nomercy/project/NodeJS/test/test.js:5:16)
    at Module._compile (node:internal/modules/cjs/loader:1198:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1252:10)
    at Module.load (node:internal/modules/cjs/loader:1076:32)
    at Function.Module._load (node:internal/modules/cjs/loader:911:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:22:47 {
  [Symbol(errorLabels)]: Set(0) {}
}

It seems I’m encountering a “MongoParseError” with the message “directConnection option requires exactly one host.” Could you please provide additional guidance on resolving this error?

Even when I use the secondary read preference (readPreference=secondary), I still encounter the same issue:

Code:

const { MongoClient } = require('mongodb');

// The MongoDB URI for the secondary member in the replica set
const uri = 'mongodb://ak:nomercy@localhost:27018/?authSource=admin&directConnection=true&readPreference=secondary';
const client = new MongoClient(uri);

async function connect() {
  try {
    await client.connect();
    console.log('Connected to MongoDB');

    const db = client.db('ak');
    const { filters } = await db.command({ planCacheListFilters: 'test' });
    filters.forEach(function (plan) {
        console.log(plan);
    });
  } catch (err) {
    console.error('Error connecting to MongoDB:', err);
  } finally {
    await client.close();
  }
}

connect();

Error:

Connected to MongoDB
Error connecting to MongoDB: MongoServerError: not primary and secondaryOk=false
    at Connection.onMessage (/home/nomercy/project/NodeJS/node_modules/mongodb/lib/cmap/connection.js:202:26)
    at MessageStream.<anonymous> (/home/nomercy/project/NodeJS/node_modules/mongodb/lib/cmap/connection.js:61:60)
    at MessageStream.emit (node:events:513:28)
    at processIncomingData (/home/nomercy/project/NodeJS/node_modules/mongodb/lib/cmap/message_stream.js:124:16)
    at MessageStream._write (/home/nomercy/project/NodeJS/node_modules/mongodb/lib/cmap/message_stream.js:33:9)
    at writeOrBuffer (node:internal/streams/writable:391:12)
    at _write (node:internal/streams/writable:332:10)
    at MessageStream.Writable.write (node:internal/streams/writable:336:10)
    at Socket.ondata (node:internal/streams/readable:754:22)
    at Socket.emit (node:events:513:28) {
  topologyVersion: { processId: new ObjectId("6503c85cdf6acceaed8673ac"), counter: 4 },
  operationTime: new Timestamp({ t: 1695004210, i: 5 }),
  ok: 0,
  code: 13435,
  codeName: 'NotPrimaryNoSecondaryOk',
  '$clusterTime': {
    clusterTime: new Timestamp({ t: 1695004210, i: 5 }),
    signature: {
      hash: Binary.createFromBase64("3nLFi7iebteJc+qLBXqQWP+hiCQ=", 0),
      keyId: new Long("7253318057697738757")
    }
  },
  [Symbol(errorLabels)]: Set(0) {}
}

Despite setting the secondary read preference, I still face the “not primary and secondaryOk=false” error. I’m seeking further assistance to resolve this issue.

Could this be an error bounced up from the secondary as it’s not enable for direct reads? How is the secondary configured? Note the error says the error comes from the server and not the driver etc.

I’ve not done this before but there are some google / SO hits that suggest others had this issue and it was a secondary config issue.

The MongoDB server and Node.js code are indeed on the same machine, and I’ve set up a two-node replica set for testing purposes. Here’s the configuration details:

  1. Primary Node (Node 1): This node is running on port 27017 and is the primary in the replica set.

  2. Secondary Node (Node 2): This node is running on port 27018 and serves as one of the secondary nodes in the replica set.

In this setup, I am trying to connect to the secondary node (Node 2) using the Node.js code. Despite setting the secondary read preference, I encountered the “not primary and secondaryOk=false” error. Below i have attached the rs.conf and rs.status output.

RS Status:


   "members" : [
      {
         "_id" : 0,
         "name" : "192.168.168.188:27017",
         "health" : 1,
         "state" : 1,
         "stateStr" : "PRIMARY",
         "uptime" : 858392,
         "optime" : {
            "ts" : Timestamp(1695040891, 1),
            "t" : NumberLong(32)
         },
         "optimeDate" : ISODate("2023-09-18T12:41:31Z"),
         "lastAppliedWallTime" : ISODate("2023-09-18T12:41:31.644Z"),
         "lastDurableWallTime" : ISODate("2023-09-18T12:41:31.644Z"),
         "syncSourceHost" : "",
         "syncSourceId" : -1,
         "infoMessage" : "",
         "electionTime" : Timestamp(1694746727, 1),
         "electionDate" : ISODate("2023-09-15T02:58:47Z"),
         "configVersion" : 59842,
         "configTerm" : 32,
         "self" : true,
         "lastHeartbeatMessage" : ""
      },
      {
         "_id" : 1,
         "name" : "192.168.168.188:27018",
         "health" : 1,
         "state" : 2,
         "stateStr" : "SECONDARY",
         "uptime" : 294169,
         "optime" : {
            "ts" : Timestamp(1695040891, 1),
            "t" : NumberLong(32)
         },
         "optimeDurable" : {
            "ts" : Timestamp(1695040891, 1),
            "t" : NumberLong(32)
         },
         "optimeDate" : ISODate("2023-09-18T12:41:31Z"),
         "optimeDurableDate" : ISODate("2023-09-18T12:41:31Z"),
         "lastAppliedWallTime" : ISODate("2023-09-18T12:41:31.644Z"),
         "lastDurableWallTime" : ISODate("2023-09-18T12:41:31.644Z"),
         "lastHeartbeat" : ISODate("2023-09-18T12:41:33.623Z"),
         "lastHeartbeatRecv" : ISODate("2023-09-18T12:41:33.617Z"),
         "pingMs" : NumberLong(1),
         "lastHeartbeatMessage" : "",
         "syncSourceHost" : "192.168.168.188:27017",
         "syncSourceId" : 0,
         "infoMessage" : "",
         "configVersion" : 59842,
         "configTerm" : 32
      }
   ],

RS Conf:

   "members" : [
      {
         "_id" : 0,
         "host" : "192.168.168.188:27017",
         "arbiterOnly" : false,
         "buildIndexes" : true,
         "hidden" : false,
         "priority" : 2,
         "tags" : {
            
         },
         "slaveDelay" : NumberLong(0),
         "votes" : 1
      },
      {
         "_id" : 1,
         "host" : "192.168.168.188:27018",
         "arbiterOnly" : false,
         "buildIndexes" : true,
         "hidden" : false,
         "priority" : 1,
         "tags" : {
            
         },
         "slaveDelay" : NumberLong(0),
         "votes" : 1
      }
   ],

Hi, Any update on this?

I am encountering a problem when executing the following command:

const { filters } = await db.command({ planCacheListFilters: 'test' });

Interestingly, when I run any ‘find’ or ‘aggregate’ query with ‘readPreference,’ it works as expected."

is there any limitation on the driver level?

I wanted to share an important observation related to a previous issue I mentioned. When using the following command:

const { filters } = await db.command({ planCacheListFilters: 'test', readPreference: 'secondary' });

I noticed that the MongoDB driver did not throw any errors, such as syntax errors, even though the command did not behave as expected. This behaviour could potentially be misleading, as it may appear that the command is valid.

After further investigation, I found that to ensure the desired behaviour, it’s necessary to specify the ‘readPreference’ both in the connection string and in the command itself, as shown below:

const { filters } = await db.command({ planCacheListFilters: 'test' }, { readPreference: 'secondary' });

It’s worked for me, after adding the flag readPreference=secondary in the database connection.

1 Like