{"id":"70d6fb31c2b63700","repo":"mongodb/node-mongodb-native","slug":"client-bulk-write-replace-models-must-not-contain","errorCode":null,"errorMessage":"Client bulk write replace models must not contain atomic modifiers (start with $) and must not be empty.","messagePattern":"Client bulk write replace models must not contain atomic modifiers \\(start with \\$\\) and must not be empty\\.","errorType":"exception","errorClass":"MongoAPIError","httpStatus":null,"severity":"error","filePath":"src/operations/client_bulk_write/command_builder.ts","lineNumber":440,"sourceCode":"  updateMods: WithoutId<Document>;\n  hint?: Hint;\n  upsert?: boolean;\n  collation?: CollationOptions;\n  sort?: SortForCmd;\n}\n\n/**\n * Build the replace one operation.\n * @param model - The replace one model.\n * @param index - The namespace index.\n * @returns the operation.\n */\nexport const buildReplaceOneOperation = (\n  model: ClientReplaceOneModel<Document>,\n  index: number\n): ClientReplaceOneOperation => {\n  if (hasAtomicOperators(model.replacement)) {\n    throw new MongoAPIError(\n      'Client bulk write replace models must not contain atomic modifiers (start with $) and must not be empty.'\n    );\n  }\n\n  const document: ClientReplaceOneOperation = {\n    update: index,\n    multi: false,\n    filter: model.filter,\n    updateMods: model.replacement\n  };\n  if (model.hint) {\n    document.hint = model.hint;\n  }\n  if (model.upsert) {\n    document.upsert = model.upsert;\n  }\n  if (model.collation) {\n    document.collation = model.collation;","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/operations/client_bulk_write/command_builder.ts#L422-L458","documentation":"Thrown when building a replaceOne model if the replacement document is empty or contains keys starting with '$'. Per spec, replaceOne MUST be a full replacement document (no atomic operators); if you want $ operators use updateOne/updateMany. Classified as MongoAPIError.","triggerScenarios":"Passing client.bulkWrite() a replaceOne model whose replacement is { $set: {...} } or {}. Mixing up updateOne and replaceOne semantics.","commonSituations":"Switching from updateOne to replaceOne but leaving $set; passing an empty replacement built from a failed mapping.","solutions":["Provide a non-empty replacement document without any '$'-prefixed keys.","If you need atomic operators, switch the model name to updateOne/updateMany.","Validate: assert Object.keys(replacement).length > 0 && !Object.keys(replacement)[0].startsWith('$')."],"exampleFix":"// before\nawait client.bulkWrite([{\n  namespace: 'db.coll',\n  name: 'replaceOne',\n  filter: { _id: 1 },\n  replacement: { $set: { a: 1 } } // wrong\n}]);\n\n// after\nawait client.bulkWrite([{\n  namespace: 'db.coll',\n  name: 'replaceOne',\n  filter: { _id: 1 },\n  replacement: { a: 1 }\n}]);","handlingStrategy":"validation","validationCode":"function isValidReplacement(doc) {\n  const keys = Object.keys(doc);\n  return keys.length > 0 && keys.every(k => !k.startsWith('$'));\n}","typeGuard":"function isPlainReplacement(v): boolean {\n  return v != null && typeof v === 'object' && Object.keys(v).every(k => !k.startsWith('$'));\n}","tryCatchPattern":null,"preventionTips":["replaceOne takes a plain document, no $ operators","Switch to updateOne if you need $set","Validate replacement is non-empty and operator-free"],"tags":["bulk-write","replace","validation","client-bulk-write"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}