175

I have a REST service built in node.js with Restify and Mongoose and a mongoDB with a collection with about 30.000 regular sized documents. I have my node service running through pmx and pm2.

Yesterday, suddenly, node started crapping out errors with the message "MongoError: Topology was destroyed", nothing more. I have no idea what is meant by this and what could have possibly triggered this. there is also not much to be found when google-searching this. So I thought I'd ask here.

After restarting the node service today, the errors stopped coming in. I also have one of these running in production and it scares me that this could happen at any given time to a pretty crucial part of the setup running there...

I'm using the following versions of the mentioned packages:

  • mongoose: 4.0.3
  • restify: 3.0.3
  • node: 0.10.25
dreagan
  • 2,426
  • 6
  • 24
  • 34

18 Answers18

105

It seems to mean your node server's connection to your MongoDB instance was interrupted while it was trying to write to it.

Take a look at the Mongo source code that generates that error

Mongos.prototype.insert = function(ns, ops, options, callback) {
    if(typeof options == 'function') callback = options, options = {};
    if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
    // Topology is not connected, save the call in the provided store to be
    // Executed at some point when the handler deems it's reconnected
    if(!this.isConnected() && this.s.disconnectHandler != null) {
      callback = bindToCurrentDomain(callback);
      return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
    }

    executeWriteOperation(this.s, 'insert', ns, ops, options, callback);
}

This does not appear to be related to the Sails issue cited in the comments, as no upgrades were installed to precipitate the crash or the "fix"

Will
  • 733
  • 8
  • 23
Jason Nichols
  • 3,739
  • 3
  • 29
  • 49
  • 2
    I have the same issue and it happens almost every week and shuts down the application working with mongo, is this some problem I generated or this is an issue in mongoose? – ganjim Apr 24 '18 at 19:12
  • @MohammadGanji: I get this error without Mongoose, while debugging client code and not being fast enough at stepping over statements. Not sure what causes it, but setting breakpoints right after the mongo queries avoids it. – Dan Dascalescu Sep 26 '18 at 22:48
  • @DanDascalescu I forgot to mention that my problem was solved, it was a problem with logging, looks like there was some warning in the logs that after sometime took about a gigabyte of storage and shut down mongo process, so I tried zipping and backing up and problem solved – ganjim Sep 29 '18 at 11:21
83

I know that Jason's answer was accepted, but I had the same problem with Mongoose and found that the service hosting my database recommended to apply the following settings in order to keep Mongodb's connection alive in production:

var options = {
  server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
  replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
};
mongoose.connect(secrets.db, options);

I hope that this reply may help other people having "Topology was destroyed" errors.

Adrien Joly
  • 5,056
  • 4
  • 28
  • 43
  • 4
    This didn't fix the problem for me. I actually ended up increasing my keepAlive to 30000, which has helped tremendously. Even though I still get the occasional topology error come in still. – ifightcrime May 18 '16 at 23:13
  • 10
    using Mongo driver from version 3.4.2, these options need to be at the top level : options: { keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000 } – Sebastien H. Apr 20 '17 at 09:01
  • I get this error without Mongoose, while debugging client code and not being fast enough at stepping over statements. Not sure what causes it, but setting breakpoints right after the mongo queries avoids it. – Dan Dascalescu Sep 26 '18 at 22:48
78

This error is due to mongo driver dropping the connection for any reason (server was down for example).

By default mongoose will try to reconnect for 30 seconds then stop retrying and throw errors forever until restarted.

You can change this by editing these 2 fields in the connection options

mongoose.connect(uri, 
    { server: { 
        // sets how many times to try reconnecting
        reconnectTries: Number.MAX_VALUE,
        // sets the delay between every retry (milliseconds)
        reconnectInterval: 1000 
        } 
    }
);

connection options documentation

gafi
  • 12,113
  • 2
  • 30
  • 32
  • 3
    Yep. Technically the accepted answer answers the question asked BUT this is the right way to avoid the scenario under discussion. – kingdango Nov 21 '16 at 19:12
  • 3
    using Mongo driver from version 3.4.2, these options need to be at the top level : options: { keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 2000 } – Sebastien H. Apr 20 '17 at 09:02
  • 1
    To clarify, according to the [documentation of the Node MongoDB Driver](http://mongodb.github.io/node-mongodb-native/2.1/api/Server.html), by default the server would attempt to reconnect 30 times, with one second apart between each retry. – Boaz Aug 03 '17 at 08:12
  • 4
    You don't need to provide these options under the server object now. It goes directly to the options objects. – Animesh Singh Oct 18 '17 at 23:34
  • 3
    Just wanted to add that recent versions of mongoose have those options in top level, so no need to add `server: {` etc. – Alex K Feb 07 '18 at 08:07
  • It seems that `reconnectTries` and `reconnectInterval` are being deprecated due to [new unified topology engine](http://mongodb.github.io/node-mongodb-native/3.3/reference/unified-topology/) of Node MongoDB driver. – Akseli Palén Oct 14 '20 at 14:25
20

In my case, this error was caused by a db.close(); out of a 'await' section inside of 'async'

MongoClient.connect(url, {poolSize: 10, reconnectTries: Number.MAX_VALUE, reconnectInterval: 1000}, function(err, db) {
    // Validate the connection to Mongo
    assert.equal(null, err);    
    // Query the SQL table 
    querySQL()
    .then(function (result) {
        console.log('Print results SQL');
        console.log(result);
        if(result.length > 0){

            processArray(db, result)
            .then(function (result) {
                console.log('Res');
                console.log(result);
            })
            .catch(function (err) {
                console.log('Err');
                console.log(err);
            })
        } else {
            console.log('Nothing to show in MySQL');
        }
    })
    .catch(function (err) {
        console.log(err);
    });
    db.close(); // <--------------------------------THIS LINE
});
Carlos Rodríguez
  • 745
  • 11
  • 20
  • 2
    In Carlos' case I guess the close happened before everything else. My case was similar: I accessed the DB after having closed it. It would be nice if the Mongo developers could produce more explicit error messages. The "Topology broken" sounds like an internal note. – Juan Lanus Sep 14 '18 at 14:51
  • 3
    your solution was to move the `db.close` into a `then` block, right? – AlexChaffee Nov 25 '18 at 17:10
  • It's correct, in my case i only delete the db.close() line, but move it into a then block seems to be a nice solution. – Carlos Rodríguez Nov 26 '18 at 18:12
  • 1
    Moving the `db.close` to a `then` block worked great for me with the native MongoDB Node.js driver. – kevinmicke Aug 20 '19 at 17:20
13

Just a minor addition to Gaafar's answer, it gave me a deprecation warning. Instead of on the server object, like this:

MongoClient.connect(MONGO_URL, {
    server: {
        reconnectTries: Number.MAX_VALUE,
        reconnectInterval: 1000
    }
});

It can go on the top level object. Basically, just take it out of the server object and put it in the options object like this:

MongoClient.connect(MONGO_URL, {
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 1000
});
Justin Grant
  • 44,807
  • 15
  • 124
  • 208
codeinaire
  • 1,682
  • 1
  • 13
  • 26
7

"Topology was destroyed" might be caused by mongoose disconnecting before mongo document indexes are created, per this comment

In order to make sure all models have their indexes built before disconnecting, you can:

await Promise.all(mongoose.modelNames().map(model => mongoose.model(model).ensureIndexes()));

await mongoose.disconnect();
golfadas
  • 5,351
  • 3
  • 32
  • 39
  • thank you, if you are running test cases - this is probably a very likely answer... – Nick Hingston Aug 13 '18 at 19:51
  • 1
    This was it for me. Thank you! I was running tests in Jest with mongodb-memory-server, getting sporadic errors on topology or open handles/unfinished Promises. But sometimes it worked. Adding a wait on indexes fixed it. – roblingle Sep 04 '18 at 12:57
  • I get this error without Mongoose, while debugging Jest code like @roblingle and not being fast enough at stepping over statements. Not sure what causes it, but setting breakpoints right after the mongo queries avoids it. – Dan Dascalescu Sep 26 '18 at 22:50
  • @roblingle how did you end up fixing it? I just ran into this problem and it made it impossible for me to connect to MongoDB again. I've since deleted everything and reinstalled MongoDB (via homebrew) and now it won't run on startup anymore. (May be an unrelated issue) – bobbyz Oct 19 '18 at 21:00
  • Sounds unrelated. My app worked fine but tests fails. – roblingle Oct 21 '18 at 21:33
  • @bobbyz Did not mean to submit that. :) Solution was the `afterAll` in my test setup file: https://gist.github.com/roblingle/25c88058079c77c520276b92711ea36c – roblingle Oct 21 '18 at 21:44
  • @roblingle Yes, it turns out the unrelated issue was regarding an update from 3.6 to 4.0. Thanks for the gist. – bobbyz Oct 21 '18 at 21:59
3

I met this in kubernetes/minikube + nodejs + mongoose environment. The problem was that DNS service was up with a kind of latency. Checking DNS is ready solved my problem.

const dns = require('dns');

var dnsTimer = setInterval(() => {
 dns.lookup('mongo-0.mongo', (err, address, family) => {
  if (err) {
   console.log('DNS LOOKUP ERR', err.code ? err.code : err);
  } else {
   console.log('DNS LOOKUP: %j family: IPv%s', address, family);
   clearTimeout(dnsTimer);
   mongoose.connect(mongoURL, db_options);
  }
 });
}, 3000);


var db = mongoose.connection;
var db_options = {
 autoReconnect:true,

 poolSize: 20,
 socketTimeoutMS: 480000,
 keepAlive: 300000,

 keepAliveInitialDelay : 300000,
 connectTimeoutMS: 30000,
 reconnectTries: Number.MAX_VALUE,
 reconnectInterval: 1000,
 useNewUrlParser: true
};

(the numbers in db_options are arbitrary found on stackoverflow and similar like sites)

tkrizsa
  • 41
  • 2
2

I alse had the same error. Finally, I found that I have some error on my code. I use load balance for two nodejs server, but I just update the code of one server.

I change my mongod server from standalone to replication, but I forget to do the corresponding update for the connection string, so I met this error.

standalone connection string: mongodb://server-1:27017/mydb replication connection string: mongodb://server-1:27017,server-2:27017,server-3:27017/mydb?replicaSet=myReplSet

details here:[mongo doc for connection string]

lutaoact
  • 4,149
  • 6
  • 29
  • 41
2

Sebastian comment on Adrien's answer needs more attention it helped me but it being a comment might be ignore sometime so here's a solution:

var options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000 }
mongoose.connect(config.mongoConnectionString, options, (err) => {
    if(err) {
        console.error("Error while connecting", err);
    }
});
Black Mamba
  • 13,632
  • 6
  • 82
  • 105
2

Here what I did, It works fine. Issue was gone after adding below options.

const dbUrl = "mongodb://localhost:27017/sampledb";
const options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000, useNewUrlParser: true }
mongoose.connect(dbUrl,options, function(
  error
) {
  if (error) {
    console.log("mongoerror", error);
  } else {
    console.log("connected");
  }

});
Thavaprakash Swaminathan
  • 6,226
  • 2
  • 30
  • 31
2

You need to restart mongo to solve the topology error, then just change some options of mongoose or mongoclient to overcome this problem:

var mongoOptions = {
    useMongoClient: true,
    keepAlive: 1,
    connectTimeoutMS: 30000,
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 5000,
    useNewUrlParser: true
}

mongoose.connect(mongoDevString,mongoOptions);
Amiga500
  • 5,874
  • 10
  • 64
  • 117
  • Welcome to SO! Please edit your answer and add some more information, i.e. how it solves the problem, for more guidance see https://stackoverflow.com/help/how-to-ask – B--rian Aug 26 '19 at 07:28
1

I got this error, while I was creating a new database on my MongoDb Compass Community. The issue was with my Mongod, it was not running. So as a fix, I had to run the Mongod command as preceding.

C:\Program Files\MongoDB\Server\3.6\bin>mongod

I was able to create a database after running that command.

Hope it helps.

Sibeesh Venu
  • 18,755
  • 12
  • 103
  • 140
1

I was struggling with this for some time - As you can see from other answers, the issue can be very different.

The easiest way to find out whats causing is this is to turn on loggerLevel: 'info' in the options

orepor
  • 905
  • 2
  • 13
  • 23
0

In my case, this error was caused by an identical server instance already running background.

The weird thing is when I started my server without notice there's one running already, the console didn't show anything like 'something is using port xxx'. I could even upload something to the server. So, it took me quite long to locate this problem.

What's more, after closing all the applications I can imagine, I still could not find the process which is using this port in my Mac's activity monitor. I have to use lsof to trace. The culprit was not surprising - it's a node process. However, with the PID shown in the terminal, I found the port number in the monitor is different from the one used by my server.

All in all, kill all the node processes may solve this problem directly.

AnLuoRidge
  • 74
  • 6
0

Using mongoose here, but you could do a similar check without it

export async function clearDatabase() {
  if (mongoose.connection.readyState === mongoose.connection.states.disconnected) {
    return Promise.resolve()
  }
  return mongoose.connection.db.dropDatabase()
}

My use case was just tests throwing errors, so if we've disconnected, I don't run operations.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Thom
  • 524
  • 1
  • 6
  • 12
0

I got this problem recently. Here what I do:

  1. Restart MongoDb: sudo service mongod restart
  2. Restart My NodeJS APP. I use pm2 to handle this pm2 restart [your-app-id]. To get ID use pm2 list
Kenjiro
  • 749
  • 1
  • 12
  • 33
0

var mongoOptions = { useNewUrlParser: true, useUnifiedTopology: true, }

mongoose.connect(mongoDevString,mongoOptions);

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 29 '22 at 15:03
-3

I solved this issue by:

  1. ensuring mongo is running
  2. restarting my server
maia
  • 3,910
  • 4
  • 27
  • 34