{"record":{"id":"000ccfdf1a07412e","repo":"mongodb/node-mongodb-native","slug":"clientsession-cannot-be-serialized-to-bson","errorCode":null,"errorMessage":"ClientSession cannot be serialized to BSON.","messagePattern":"ClientSession cannot be serialized to BSON\\.","errorType":"exception","errorClass":"MongoRuntimeError","httpStatus":null,"severity":"error","filePath":"src/sessions.ts","lineNumber":676,"sourceCode":"          }\n          // we do not retry the retry\n        }\n      }\n\n      // The spec indicates that if the operation times out or fails with a non-retryable error, we should ignore all errors on `abortTransaction`\n    } finally {\n      this.transaction.transition(TxnState.TRANSACTION_ABORTED);\n      if (this.loadBalanced) {\n        maybeClearPinnedConnection(this, { force: false });\n      }\n    }\n  }\n\n  /**\n   * This is here to ensure that ClientSession is never serialized to BSON.\n   */\n  toBSON(): never {\n    throw new MongoRuntimeError('ClientSession cannot be serialized to BSON.');\n  }\n\n  /**\n   * Starts a transaction and runs a provided function, ensuring the commitTransaction is always attempted when all operations run in the function have completed.\n   *\n   * **IMPORTANT:** This method requires the function passed in to return a Promise. That promise must be made by `await`-ing all operations in such a way that rejections are propagated to the returned promise.\n   *\n   * **IMPORTANT:** Running operations in parallel is not supported during a transaction. The use of `Promise.all`,\n   * `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a transaction is\n   * undefined behaviour.\n   *\n   * **IMPORTANT:** When running an operation inside a `withTransaction` callback, if it is not\n   * provided the explicit session in its options, it will not be part of the transaction and it will not respect timeoutMS.\n   *\n   *\n   * @remarks\n   * - If all operations successfully complete and the `commitTransaction` operation is successful, then the provided function will return the result of the provided function.\n   * - If the transaction is unable to complete or an error is thrown from within the provided function, then the provided function will throw an error.","sourceCodeStart":658,"sourceCodeEnd":694,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/sessions.ts#L658-L694","documentation":"ClientSession defines `toBSON(): never` that always throws MongoRuntimeError (sessions.ts:675). The BSON serializer calls `toBSON()` on any object that defines it, so accidentally embedding a ClientSession in a document being inserted/updated/replaced triggers this guard. It exists precisely to catch the common mistake of passing `{ session }` as a field rather than as an option.","triggerScenarios":"`collection.insertOne({ session, ...data }, { session })` — the session object ends up as a document field; similarly for updateOne/replaceOne/aggregate stages that embed the session by mistake. Spreads like `collection.insertOne({ ...reqBody })` where `reqBody` happens to contain a session reference.","commonSituations":"Mixing up the session-as-option vs. session-as-document; spreading a request body that was decorated with a session; passing a document that includes a nested entity holding a session.","solutions":["Pass the session only as an option, never as a document field: `insertOne(doc, { session })`.","Audit spreads: build the document explicitly and strip session-like references before insert.","If you must carry context, store a session id (string) in the document, not the session object."],"exampleFix":"// before\nawait collection.insertOne({ session, name: 'x' }, { session });\n\n// after\nawait collection.insertOne({ name: 'x' }, { session });","handlingStrategy":"type-guard","validationCode":"import { ClientSession } from 'mongodb';\n\nfunction stripSessions(doc) {\n  for (const k of Object.keys(doc)) {\n    if (doc[k] instanceof ClientSession) delete doc[k];\n    else if (doc[k] && typeof doc[k] === 'object') stripSessions(doc[k]);\n  }\n  return doc;\n}\nawait collection.insertOne(stripSessionFields(payload), { session });","typeGuard":"import { ClientSession } from 'mongodb';\nfunction hasSessionValue(v) {\n  if (v instanceof ClientSession) return true;\n  if (v && typeof v === 'object') {\n    return Object.values(v).some(hasSessionValue);\n  }\n  return false;\n}","tryCatchPattern":null,"preventionTips":["Pass the session only as the second argument option, never as a document field.","Be careful with spreads of request bodies that may carry a session reference.","Add a unit test that asserts inserted documents never contain a ClientSession."],"tags":["sessions","bson","common-mistake","serialization"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}