mongodb/node-mongodb-native · error · MongoRuntimeError
client.connect did not create a topology but also did not…
Error message
client.connect did not create a topology but also did not throw
What it means
Thrown as a MongoRuntimeError from autoConnect() after await client.connect() resolves successfully yet client.topology is still null. This is a defensive invariant check: connect() is contract-bound to either populate the topology or throw, so reaching this line means the driver is in an impossible internal state. It almost always indicates a concurrent close(), a mocked/improperly overridden connect(), or a genuine driver bug rather than normal user error.
Solutions
- Ensure no concurrent client.close() races with the first operation; await connect() before any operation or before closing.
- If mocking MongoClient in tests, make the stub set a topology or throw, matching the real contract.
- Avoid calling connect() manually and then operations on the same client from different async branches without awaiting.
- If using a real client, upgrade the driver version and report the issue with a reproduction if it persists.
Example fix
// before
const client = new MongoClient(uri);
const p1 = client.db('x').collection('y').insertOne({a:1}); // triggers autoConnect
await client.close(); // races with connect -> error 300
await p1;
// after
const client = new MongoClient(uri);
await client.connect();
try {
await client.db('x').collection('y').insertOne({a:1});
} finally {
await client.close();
} Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure connect() completes before any concurrent close
import type { MongoClient } from 'mongodb';
async function safeRun(client: MongoClient, fn: () => Promise<void>) {
if (client.topology == null) {
await client.connect(); // await fully before operating/closing
}
await fn();
} Try / catch
try {
await client.connect();
await client.db('x').collection('y').insertOne({ a: 1 });
} catch (err) {
if (err instanceof MongoRuntimeError && /did not create a topology/.test(err.message)) {
// concurrent close or stub issue; reconnect or report
} else {
throw err;
}
} finally {
await client.close();
} Prevention
- Never call client.close() concurrently with the first operation; await connect() first.
- Do not partially mock MongoClient.connect() in tests; set a topology or throw.
- Treat connect/close as critical sections separated by awaits.
When it happens
Trigger: Any operation invoked on a MongoClient that has not yet connected triggers autoConnect (execute_operation.ts:76). If client.close() runs concurrently during that connect, or a test stub of MongoClient.connect() resolves without building a topology, this guard fires at execute_operation.ts:153.
Common situations: Calling client.close() in a race with the first operation; unit tests that mock MongoClient.connect() incompletely; a MongoClient subclass that overrides connect() without setting this.s.topology; double-connect/close interleaving in async initialization code.
Related errors
- A collection name must be determined before getMore
- A collection name must be determined before killCursors
- An unexpected error type
- Argument "setName" is required if connected to a replica set
- Azure endpoint did not return a value with only…
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/333c1ca9548f8997.
Report an issue: GitHub.
Appendix: source
Thrown at src/operations/execute_operation.ts:153
await session.endSession();
}
}
}
/**
* Connects a client if it has not yet been connected
* @internal
*/
export async function autoConnect(client: MongoClient): Promise<Topology> {
if (client.topology == null) {
if (client.s.hasBeenClosed) {
throw new MongoNotConnectedError('Client must be connected before running operations');
}
client.s.options.__skipPingOnConnect = true;
try {
await client.connect();
if (client.topology == null) {
throw new MongoRuntimeError(
'client.connect did not create a topology but also did not throw'
);
}
return client.topology;
} finally {
delete client.s.options.__skipPingOnConnect;
}
}
return client.topology;
}
/** @internal */
type RetryOptions = {
session: ClientSession | undefined;
readPreference: ReadPreference;
topology: Topology;
timeoutContext: TimeoutContext;
};View on GitHub (pinned to dce7939f86)