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

  1. Ensure no concurrent client.close() races with the first operation; await connect() before any operation or before closing.
  2. If mocking MongoClient in tests, make the stub set a topology or throw, matching the real contract.
  3. Avoid calling connect() manually and then operations on the same client from different async branches without awaiting.
  4. 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

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


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)