{"id":"c7b4d995bb4e67ea","repo":"mongodb/node-mongodb-native","slug":"client-bulk-write-update-models-must-only-contain","errorCode":null,"errorMessage":"Client bulk write update models must only contain atomic modifiers (start with $) and must not be empty.","messagePattern":"Client bulk write update models must only 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":373,"sourceCode":" * @param model - The update many model.\n * @param index - The namespace index.\n * @returns the operation.\n */\nexport const buildUpdateManyOperation = (\n  model: ClientUpdateManyModel<Document>,\n  index: number,\n  options: BSONSerializeOptions\n): ClientUpdateOperation => {\n  return createUpdateOperation(model, index, true, options);\n};\n\n/**\n * Validate the update document.\n * @param update - The update document.\n */\nfunction validateUpdate(update: Document, options: BSONSerializeOptions) {\n  if (!hasAtomicOperators(update, options)) {\n    throw new MongoAPIError(\n      'Client bulk write update models must only contain atomic modifiers (start with $) and must not be empty.'\n    );\n  }\n}\n\n/**\n * Creates a delete operation based on the parameters.\n */\nfunction createUpdateOperation(\n  model: ClientUpdateOneModel<Document> | ClientUpdateManyModel<Document>,\n  index: number,\n  multi: boolean,\n  options: BSONSerializeOptions\n): ClientUpdateOperation {\n  // Update documents provided in UpdateOne and UpdateMany write models are\n  // required only to contain atomic modifiers (i.e. keys that start with \"$\").\n  // Drivers MUST throw an error if an update document is empty or if the\n  // document's first key does not start with \"$\".","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/operations/client_bulk_write/command_builder.ts#L355-L391","documentation":"Thrown by validateUpdate() when an updateOne/updateMany model's update document is empty or its first key does not start with '$'. Per the cross-driver spec, update operations in client bulk writes MUST use atomic operators ($set, $inc, etc.); replacement-style documents are not allowed here (use replaceOne instead). Classified as MongoAPIError.","triggerScenarios":"Passing client.bulkWrite() an updateOne/updateMany model whose update is { field: value } (no $ operator) or {} (empty). Accidentally using a replacement document where an atomic update was intended.","commonSituations":"Treating updateOne like replaceOne; building update dynamically and ending with an empty object; copy-paste from collection.updateOne that accepted full replacements in older patterns.","solutions":["Wrap the fields in $set: update: { $set: { field: value } }.","Use a replaceOne model if you intend a full-document replacement.","Validate before sending: assert model.update && Object.keys(model.update)[0]?.startsWith('$')."],"exampleFix":"// before\nawait client.bulkWrite([{\n  namespace: 'db.coll',\n  name: 'updateOne',\n  filter: { _id: 1 },\n  update: { status: 'done' } // no $ operator\n}]);\n\n// after\nawait client.bulkWrite([{\n  namespace: 'db.coll',\n  name: 'updateOne',\n  filter: { _id: 1 },\n  update: { $set: { status: 'done' } }\n}]);","handlingStrategy":"validation","validationCode":"function isValidUpdate(update) {\n  const keys = Object.keys(update);\n  return keys.length > 0 && keys[0].startsWith('$');\n}","typeGuard":"function isAtomicUpdate(v): boolean {\n  return v != null && typeof v === 'object' && Object.keys(v).every(k => k.startsWith('$'));\n}","tryCatchPattern":null,"preventionTips":["Always use $set/$inc etc. for updateOne/updateMany","Use replaceOne for full-document replacement","Validate the update has at least one $ key before sending"],"tags":["bulk-write","update","validation","client-bulk-write","atomic-operators"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}