mongodb/node-mongodb-native · error · MongoInvalidArgumentError

ClientSession must be from the same MongoClient

Error message

ClientSession must be from the same MongoClient

What it means

Thrown when a ClientSession passed to an operation was created by a different MongoClient than the one executing the operation. The driver pins each session to the client that started it (session.client), because sessions carry server-side transaction state tied to that client's connection pool.

Solutions

  1. Use the same MongoClient for both startSession and the operation.
  2. If you truly need two clients, start a separate session on each — server-side transactions cannot span them.
  3. Audit session propagation through your data-access layer to ensure the originating client follows the session.

Example fix

// before
const session = clientA.startSession();
await clientB.collection.find({}, { session }).next();

// after
const session = clientB.startSession();
await clientB.collection.find({}, { session }).next();
Defensive patterns

Strategy: validation

Validate before calling

if (session && session.client !== client) {
  throw new Error('ClientSession must come from the same MongoClient');
}
await collection.findOne({}, { session });

Prevention

When it happens

Trigger: Creating a session with clientA.startSession() and then passing it to an operation on clientB (e.g. clientB.db('x').collection('y').find({}, { session })).

Common situations: Multi-tenant apps that maintain one client per tenant but share session objects; connection-pool sharding helpers that route operations across clients; copy-pasting session plumbing between modules that use different clients.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/9a4f2ef0efba36d8. Report an issue: GitHub.

Appendix: source

Thrown at src/operations/execute_operation.ts:95

      : client.topology;

  // The driver sessions spec mandates that we implicitly create sessions for operations
  // that are not explicitly provided with a session.
  let session = operation.session;
  let owner: symbol | undefined;

  if (session == null) {
    owner = Symbol();
    session = client.startSession({ owner, explicit: false });
  } else if (session.hasEnded) {
    throw new MongoExpiredSessionError('Use of expired sessions is not permitted');
  } else if (
    session.snapshotEnabled &&
    maxWireVersion(topology) < MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION
  ) {
    throw new MongoCompatibilityError('Snapshot reads require MongoDB 5.0 or later');
  } else if (session.client !== client) {
    throw new MongoInvalidArgumentError('ClientSession must be from the same MongoClient');
  }

  operation.session ??= session;

  const readPreference = operation.readPreference ?? ReadPreference.primary;
  const inTransaction = !!session?.inTransaction();

  const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION);

  if (
    inTransaction &&
    !readPreference.equals(ReadPreference.primary) &&
    (hasReadAspect || operation.commandName === 'runCommand')
  ) {
    throw new MongoTransactionError(
      `Read preference in a transaction must be primary, not: ${readPreference.mode}`
    );
  }

View on GitHub (pinned to dce7939f86)