What it means
A MongoClient keeps a picture of the servers it talks to (the driver calls it the topology) and
a pool of connections to them. client.close() shuts that down. Anything still waiting on it, such
as connect() or a query that hasn’t been given a server yet, fails with
MongoTopologyClosedError: Topology is closed. It comes from the driver, not from MongoDB: the
server never saw the operation.
Closing at the wrong moment shows up in a few forms, depending on where the operation was when the client closed:
| Message | When |
|---|---|
MongoTopologyClosedError: Topology is closed | close() ran while connect() or a query was waiting for a server |
MongoNotConnectedError: Client must be connected before running operations | A query ran after close() had finished |
MongoExpiredSessionError: Cannot use a session that has ended | A query started while close() was still running |
MongoClientClosedError: Operation interrupted because client was closed | close() ran while a query was running on the server (driver 6.20) |
Common causes
- A missing
await.client.close()in afinallyblock runs before a query that wasn’t awaited, orclose()itself isn’t awaited and the next request uses the client. - A client closed per request. A handler closes the shared client when it’s done, while other requests are still using it.
- Serverless functions that close the client at the end of an invocation and reuse the same module-level client in the next one.
- Tests.
afterAllcloses the client while a query from a test that didn’t await it is still pending, or one test file closes a client another file shares. - The server can’t be reached. While the driver waits up to 30 seconds for a server, any
close()(from a shutdown handler or a test timeout) turns the wait into this error. The real problem is the connection: see server selection errors.
How to fix it
Create one client and close it at shutdown
A MongoClient is meant to be shared: it manages its own pool. Create it once when the app starts,
reuse it everywhere, and close it only when the process ends:
const { MongoClient } = require("mongodb")
const client = new MongoClient(process.env.MONGODB_URI)
const db = client.db("shop")
process.on("SIGTERM", async () => {
await client.close()
process.exit(0)
})
connect() is optional since driver 4.7: the first operation connects. Don’t call close() in a
request handler.
Await everything before closing
In scripts, make sure every operation has finished first:
try {
await orders.insertMany(docs)
await orders.createIndex({ placedAt: -1 })
} finally {
await client.close()
}
With Promise.all, await the whole set before the finally runs. A lint rule such as
@typescript-eslint/no-floating-promises finds promises nobody awaited.
Reuse the client in serverless functions
Create the client outside the handler and don’t close it at the end of each call, so a warm function reuses its connections.
In tests, close in one place
Share one client across a test file, close it in afterAll, and await every query in the tests.
Fix the connection if nothing was reachable
If the error comes after a long pause, add serverSelectionTimeoutMS=5000 to the URL so the real
cause (ECONNREFUSED, ENOTFOUND, a timeout) appears within five seconds instead of being cut off
by close().
Reproduce it
Node.js 25 with the Node.js driver 6.20.0, against the MongoDB 8.0.32 test server. A client pointed at a port where nothing listens, closed half a second after a query started:
const client = new MongoClient("mongodb://localhost:37099/?serverSelectionTimeoutMS=5000")
const pending = client.db("shop").collection("orders").findOne({})
setTimeout(() => client.close(), 500)
await pending
MongoTopologyClosedError: Topology is closed
A client for the working server, closed without awaiting the connect() before it:
const connecting = client.connect()
client.close()
await connecting
MongoTopologyClosedError: Topology is closed
A query after that close had finished:
MongoNotConnectedError: Client must be connected before running operations
client.close() not awaited, then a query straight away:
MongoExpiredSessionError: Cannot use a session that has ended
A query running a slow $where on the server when close() ran gave
MongoClientClosedError: Operation interrupted because client was closed with the driver 6.20.0;
with 6.16.0 the query finished first. Driver 6.16.0 gave the same messages for the other cases. A
client never connected explicitly ran its query without an error.
In Inlet
Paste the connection URL your app uses (mongodb:// or mongodb+srv://) and Inlet fills the
connection form, so you can check the server answers outside your code. Collections show as tables
and queries use mongosh syntax, so you can confirm what a script wrote before it closed.