mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Update document requires atomic operators

Error message

Update document requires atomic operators

What it means

Thrown by FindOperators.updateOne() when the update document does not begin with an atomic operator (e.g. $set, $inc, $unset). The driver validates the first key of the document (or every doc if an array/pipeline of plain objects) starts with '$' via hasAtomicOperators(). MongoDB updateOne commands require an update operator or an aggregation pipeline; a plain replacement document is not accepted by this method (use replaceOne for that).

Source

Thrown at src/bulk/common.ts:736

    this.bulkOperation = bulkOperation;
  }

  /** Add a multiple update operation to the bulk operation */
  update(updateDocument: Document | Document[]): BulkOperationBase {
    const currentOp = buildCurrentOp(this.bulkOperation);
    return this.bulkOperation.addToOperationsList(
      BatchType.UPDATE,
      makeUpdateStatement(currentOp.selector, updateDocument, {
        ...currentOp,
        multi: true
      })
    );
  }

  /** Add a single update operation to the bulk operation */
  updateOne(updateDocument: Document | Document[]): BulkOperationBase {
    if (!hasAtomicOperators(updateDocument, this.bulkOperation.bsonOptions)) {
      throw new MongoInvalidArgumentError('Update document requires atomic operators');
    }

    const currentOp = buildCurrentOp(this.bulkOperation);
    return this.bulkOperation.addToOperationsList(
      BatchType.UPDATE,
      makeUpdateStatement(currentOp.selector, updateDocument, { ...currentOp, multi: false })
    );
  }

  /** Add a replace one operation to the bulk operation */
  replaceOne(replacement: Document): BulkOperationBase {
    if (hasAtomicOperators(replacement)) {
      throw new MongoInvalidArgumentError('Replacement document must not use atomic operators');
    }

    const currentOp = buildCurrentOp(this.bulkOperation);
    return this.bulkOperation.addToOperationsList(
      BatchType.UPDATE,

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Wrap the replacement fields in { $set: { ... } } before passing to updateOne.
  2. If you intend to replace the whole document, use bulk.find(filter).replaceOne(doc) instead.
  3. For computed/aggregation updates, pass an array pipeline like [{ $set: { total: { $sum: [...] } } }] (the first key '$set' satisfies the check).

Example fix

// before
bulk.find({ _id: 1 }).updateOne({ name: 'alice' });

// after
bulk.find({ _id: 1 }).updateOne({ $set: { name: 'alice' } });
Defensive patterns

Strategy: validation

Validate before calling

import { hasAtomicOperators } from 'mongodb';

function assertUpdateDoc(doc) {
  if (!hasAtomicOperators(doc)) {
    throw new TypeError('updateOne requires an atomic operator like $set');
  }
}

Type guard

function isAtomicUpdate(doc) {
  return (
    doc != null &&
    typeof doc === 'object' &&
    (Array.isArray(doc)
      ? doc.length > 0
      : Object.keys(doc).length > 0 && Object.keys(doc)[0][0] === '$')
  );
}

Try / catch

try {
  bulk.find(filter).updateOne(updateDoc);
} catch (e) {
  if (e instanceof MongoInvalidArgumentError && /atomic operators/.test(e.message)) {
    // wrap in $set and retry, or surface a clearer error
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling bulk.find(filter).updateOne(doc) where doc is a plain object like { field: value } without a leading $-prefixed key, or where doc is an empty object {}. Passing a replacement-style document to updateOne instead of replaceOne.

Common situations: Developers coming from SQL or other ORMs who construct the update body as a literal document; refactoring a replaceOne call into updateOne without adding $set; dynamically building update docs where the operator key is dropped by mistake.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/b9f0852e51f2fb25.json. Report an issue: GitHub.