{"record":{"id":"9a4f2ef0efba36d8","repo":"mongodb/node-mongodb-native","slug":"clientsession-must-be-from-the-same-mongoclient","errorCode":null,"errorMessage":"ClientSession must be from the same MongoClient","messagePattern":"ClientSession must be from the same MongoClient","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/operations/execute_operation.ts","lineNumber":95,"sourceCode":"      : client.topology;\n\n  // The driver sessions spec mandates that we implicitly create sessions for operations\n  // that are not explicitly provided with a session.\n  let session = operation.session;\n  let owner: symbol | undefined;\n\n  if (session == null) {\n    owner = Symbol();\n    session = client.startSession({ owner, explicit: false });\n  } else if (session.hasEnded) {\n    throw new MongoExpiredSessionError('Use of expired sessions is not permitted');\n  } else if (\n    session.snapshotEnabled &&\n    maxWireVersion(topology) < MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION\n  ) {\n    throw new MongoCompatibilityError('Snapshot reads require MongoDB 5.0 or later');\n  } else if (session.client !== client) {\n    throw new MongoInvalidArgumentError('ClientSession must be from the same MongoClient');\n  }\n\n  operation.session ??= session;\n\n  const readPreference = operation.readPreference ?? ReadPreference.primary;\n  const inTransaction = !!session?.inTransaction();\n\n  const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION);\n\n  if (\n    inTransaction &&\n    !readPreference.equals(ReadPreference.primary) &&\n    (hasReadAspect || operation.commandName === 'runCommand')\n  ) {\n    throw new MongoTransactionError(\n      `Read preference in a transaction must be primary, not: ${readPreference.mode}`\n    );\n  }","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/operations/execute_operation.ts#L77-L113","documentation":"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.","triggerScenarios":"Creating a session with clientA.startSession() and then passing it to an operation on clientB (e.g. clientB.db('x').collection('y').find({}, { session })).","commonSituations":"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.","solutions":["Use the same MongoClient for both startSession and the operation.","If you truly need two clients, start a separate session on each — server-side transactions cannot span them.","Audit session propagation through your data-access layer to ensure the originating client follows the session."],"exampleFix":"// before\nconst session = clientA.startSession();\nawait clientB.collection.find({}, { session }).next();\n\n// after\nconst session = clientB.startSession();\nawait clientB.collection.find({}, { session }).next();","handlingStrategy":"validation","validationCode":"if (session && session.client !== client) {\n  throw new Error('ClientSession must come from the same MongoClient');\n}\nawait collection.findOne({}, { session });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep session and operation on the same MongoClient instance.","In multi-tenant code, route sessions through the same client selector as the operations."],"tags":["sessions","multi-client","api-misuse"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}