{"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/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/sessions.ts#L658-L694","documentation":"ClientSession defines a toBSON() method that unconditionally throws a MongoRuntimeError. This is a deliberate guard: BSON serialization invokes toBSON() on objects that define it, so if a ClientSession is embedded as a field value in a document being inserted/updated, BSON would otherwise silently serialize it (or fail opaquely). The guard makes the misuse loud and immediate.","triggerScenarios":"Inserting/updating a document that contains a ClientSession reference as a property value, e.g. { user: 'x', session } passed to insertOne instead of { session } as the options bag. Also spreading a session into a doc by accident, or storing it on an object that is later serialized.","commonSituations":"Passing the wrong argument shape to insertOne/updateOne (session mixed into the document); destructuring session into a payload object; middleware that attaches the session to req and later persists req.","solutions":["Move the session out of the document and into the options argument: coll.insertOne(doc, { session }).","Audit the document body for stray session references before writing; strip keys that are ClientSession instances.","Use a type guard to assert no field of the document is a ClientSession before insert."],"exampleFix":"// before\nconst session = client.startSession();\nawait coll.insertOne({ name: 'x', session }, { session }); // 'session' key in doc throws\n\n// after\nconst session = client.startSession();\nawait coll.insertOne({ name: 'x' }, { session });","handlingStrategy":"type-guard","validationCode":"import { ClientSession } from 'mongodb';\nfunction hasSessionValue(doc: unknown): boolean {\n  if (doc == null || typeof doc !== 'object') return false;\n  return Object.values(doc).some(v => v instanceof ClientSession);\n}\nif (!hasSessionValue(myDoc)) {\n  await coll.insertOne(myDoc, { session });\n}","typeGuard":"import { ClientSession } from 'mongodb';\nfunction isClientSession(v: unknown): v is ClientSession {\n  return v instanceof ClientSession;\n}","tryCatchPattern":"try {\n  await coll.insertOne(doc, { session });\n} catch (e) {\n  if (e instanceof MongoRuntimeError && /cannot be serialized to BSON/.test(e.message)) {\n    // a ClientSession leaked into the doc body; strip session-shaped values and retry\n  } else throw e;\n}","preventionTips":["Always pass session as the options bag ({ session }), never as a document field.","Audit document bodies constructed from destructured objects that might include a session.","Add a pre-write assertion that no enumerable value is a ClientSession."],"tags":["sessions","bson","serialization","runtime","guard"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}