{"record":{"id":"0b5654b5e3f68fa1","repo":"mongodb/node-mongodb-native","slug":"update-document-requires-atomic-operators-0b5654","errorCode":null,"errorMessage":"Update document requires atomic operators","messagePattern":"Update document requires atomic operators","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/operations/find_and_modify.ts","lineNumber":278,"sourceCode":"  override options: FindOneAndUpdateOptions;\n\n  private update: Document;\n  constructor(\n    collection: Collection,\n    filter: Document,\n    update: Document,\n    options: FindOneAndUpdateOptions\n  ) {\n    if (filter == null || typeof filter !== 'object') {\n      throw new MongoInvalidArgumentError('Argument \"filter\" must be an object');\n    }\n\n    if (update == null || typeof update !== 'object') {\n      throw new MongoInvalidArgumentError('Argument \"update\" must be an object');\n    }\n\n    if (!hasAtomicOperators(update, options)) {\n      throw new MongoInvalidArgumentError('Update document requires atomic operators');\n    }\n\n    super(collection, filter, options);\n    this.update = update;\n    this.options = options;\n  }\n\n  override buildCommandDocument(\n    connection: Connection,\n    session?: ClientSession\n  ): Document & FindAndModifyCmdBase {\n    const document = super.buildCommandDocument(connection, session);\n    document.update = this.update;\n    configureFindAndModifyCmdBaseUpdateOpts(document, this.options);\n\n    if (this.options.arrayFilters) {\n      document.arrayFilters = this.options.arrayFilters;\n    }","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/operations/find_and_modify.ts#L260-L296","documentation":"Thrown as a MongoInvalidArgumentError by the FindOneAndUpdateOperation constructor when the update document has no keys beginning with '$' (no atomic operators). findOneAndUpdate performs field-level modifications, so the update must contain operators like $set, $inc, $push, or be an aggregation pipeline (handled separately). The check is `!hasAtomicOperators(update, options)` at find_and_modify.ts:277.","triggerScenarios":"Calling collection.findOneAndUpdate(filter, { field: value }) with a plain replacement-style document instead of { $set: { field: value } }. Any update object whose first key does not start with '$' triggers this.","commonSituations":"Confusing update (operators) with replacement (full document); omitting the $set wrapper; passing a full document intended for replaceOne.","solutions":["Wrap field changes in $set: collection.findOneAndUpdate(filter, { $set: { field: value } }).","If you intended a full-document replace, use findOneAndReplace or replaceOne instead.","For aggregation-based updates, pass a pipeline array of stages."],"exampleFix":"// before\nawait collection.findOneAndUpdate({ _id: id }, { status: 'done' });\n\n// after\nawait collection.findOneAndUpdate({ _id: id }, { $set: { status: 'done' } });","handlingStrategy":"validation","validationCode":"function hasAtomicOperators(doc: Record<string, unknown>): boolean {\n  const keys = Object.keys(doc);\n  return keys.length > 0 && keys[0].startsWith('$');\n}\nif (!hasAtomicOperators(update)) {\n  throw new TypeError('update must contain atomic operators like $set; for full replace use findOneAndReplace');\n}\nawait collection.findOneAndUpdate(filter, update);","typeGuard":"function isUpdateDoc(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n    && Object.keys(v).some(k => k.startsWith('$'));\n}","tryCatchPattern":null,"preventionTips":["Wrap field changes in $set (or another operator) for findOneAndUpdate.","Use findOneAndReplace if you intend a full-document replace.","Add a preflight operator check when building updates from user input."],"tags":["validation","find-one-and-update","atomic-operators","update","argument"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}