{"id":"d86a8998dd381917","repo":"mongodb/node-mongodb-native","slug":"could-not-serialize-operation-to-bson","errorCode":null,"errorMessage":"Could not serialize operation to BSON","messagePattern":"Could not serialize operation to BSON","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/operations/client_bulk_write/command_builder.ts","lineNumber":136,"sourceCode":"\n    while (this.currentModelIndex < this.models.length) {\n      const model = this.models[this.currentModelIndex];\n      const ns = model.namespace;\n      const nsIndex = namespaces.get(ns);\n\n      // Multi updates are not retryable.\n      if (model.name === 'deleteMany' || model.name === 'updateMany') {\n        this.isBatchRetryable = false;\n      }\n\n      if (nsIndex != null) {\n        // Build the operation and serialize it to get the bytes buffer.\n        const operation = buildOperation(model, nsIndex, this.pkFactory, this.options);\n        let operationBuffer;\n        try {\n          operationBuffer = BSON.serialize(operation);\n        } catch (cause) {\n          throw new MongoInvalidArgumentError(`Could not serialize operation to BSON`, { cause });\n        }\n\n        validateBufferSize('ops', operationBuffer, maxBsonObjectSize);\n\n        // Check if the operation buffer can fit in the command. If it can,\n        // then add the operation to the document sequence and increment the\n        // current length as long as the ops don't exceed the maxWriteBatchSize.\n        if (\n          commandLength + operationBuffer.length < maxMessageSizeBytes &&\n          command.ops.documents.length < maxWriteBatchSize\n        ) {\n          // Pushing to the ops document sequence returns the total byte length of the document sequence.\n          commandLength = MESSAGE_OVERHEAD_BYTES + command.ops.push(operation, operationBuffer);\n          // Increment the builder's current model index.\n          this.currentModelIndex++;\n        } else {\n          // The operation cannot fit in the current command and will need to\n          // go in the next batch. Exit the loop.","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/operations/client_bulk_write/command_builder.ts#L118-L154","documentation":"Thrown while building a client bulk write command when BSON.serialize() fails on a per-model operation document. The underlying serialization error is attached as `cause`. Typical causes are values BSON cannot encode: undefined nested values (depending on ignoreUndefined), circular references, custom class instances, symbols, BigInt beyond int64, or functions.","triggerScenarios":"Passing client.bulkWrite() a model whose filter/update/document contains a non-serializable value: circular object, class instance, Map/Set, symbol keys, undefined where not allowed, or a value exceeding BSON type limits.","commonSituations":"Inserting ORM/Mongoose documents directly; objects with circular refs after JSON.parse of revivers; accidentally including function properties; using Decimal128/BSON types incorrectly.","solutions":["Inspect err.cause for the exact field and BSON type error, then sanitize that value.","Strip non-serializable keys (functions, symbols, undefined) before building the model, or convert class instances to plain objects.","Break circular references or use a custom serializer; consider ignoreUndefined if undefined handling is the issue."],"exampleFix":"// before\nawait client.bulkWrite([{\n  namespace: 'db.coll',\n  name: 'insertOne',\n  document: someMongooseDoc // class instance, fails BSON\n}]);\n\n// after\nawait client.bulkWrite([{\n  namespace: 'db.coll',\n  name: 'insertOne',\n  document: someMongooseDoc.toObject()\n}]);","handlingStrategy":"validation","validationCode":"function toPlain(v) {\n  return v == null || typeof v !== 'object' ? v\n    : Array.isArray(v) ? v.map(toPlain)\n    : Object.fromEntries(Object.entries(v).filter(([,x]) => x !== undefined && typeof x !== 'function').map(([k,x]) => [k, toPlain(x)]));\n}","typeGuard":"function isPlainSerializable(v): boolean {\n  if (v === undefined || typeof v === 'function' || typeof v === 'symbol') return false;\n  if (typeof v !== 'object') return true;\n  try { JSON.stringify(v); return true; } catch { return false; }\n}","tryCatchPattern":"try { await client.bulkWrite(models); } catch (e) {\n  if (e instanceof MongoInvalidArgumentError && /serialize operation/.test(e.message)) {\n    console.error('Serialization failed:', e.cause);\n  }\n  throw e;\n}","preventionTips":["Convert ORM/Mongoose docs to plain objects first","Strip undefined/function/symbol keys","Inspect err.cause for the failing field","Avoid circular references"],"tags":["bulk-write","bson","serialization","client-bulk-write"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}