mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Update document requires atomic operators
Error message
Update document requires atomic operators
What it means
Thrown as MongoInvalidArgumentError by FindOperators.updateOne() (src/bulk/common.ts:736) when the update document passed to bulkOp.find(filter).updateOne(doc) contains no MongoDB atomic operators ($set, $inc, $push, etc.). The driver requires update pipelines or update-operator documents for updateOne so it can build a correct OP_MSG update statement; a bare field document would be ambiguous and is rejected up front.
Solutions
- Wrap the fields you want to change in an atomic operator, most commonly $set: updateOne({ $set: { status: 'active' } }).
- If you actually intend to replace the whole document, use replaceOne(...) instead of updateOne(...).
- If you want aggregation-style updates, pass an array pipeline: updateOne([{ $set: { total: { $sum: ['$a','$b'] } } }]) (pipelines are detected as operator-bearing).
- Double-check any dynamic builder that constructs the update object to ensure the $-prefixed key survives the spread/merge.
Example fix
// before
bulk.find({ _id: 1 }).updateOne({ status: 'active' });
// after
bulk.find({ _id: 1 }).updateOne({ $set: { status: 'active' } }); Defensive patterns
Strategy: validation
Validate before calling
import { hasAtomicOperators } from 'mongodb'; // internal helper, mirror locally if not exported
function isValidUpdateOne(doc: unknown): boolean {
return (
doc != null &&
typeof doc === 'object' &&
(Array.isArray(doc)
? doc.every(d => hasAtomicOperators(d))
: hasAtomicOperators(doc))
);
}
if (!isValidUpdateOne(updateDoc)) {
throw new Error('updateOne body must use atomic operators like $set');
} Type guard
function isUpdateBody(doc: unknown): doc is Record<string, unknown> | Record<string, unknown>[] {
if (doc == null || typeof doc !== 'object') return false;
if (Array.isArray(doc)) return doc.every(d => isUpdateBody(d));
return Object.keys(doc as Record<string, unknown>).some(k => k.startsWith('$'));
} Try / catch
try {
bulk.find(filter).updateOne(updateDoc);
} catch (e) {
if (e instanceof MongoInvalidArgumentError && /atomic operators/.test(e.message)) {
updateDoc = { $set: updateDoc };
bulk.find(filter).updateOne(updateDoc);
} else throw e;
} Prevention
- Always wrap update fields in $set/$inc/etc. for updateOne/updateMany/update.
- Keep replace-style builders separate from update-style builders to avoid leaking.
- Add a unit test asserting updateOne bodies start with a $-prefixed key.
- When constructing updates dynamically, type the result as Record<`$${string}`, unknown>.
When it happens
Trigger: Calling bulkOp.find({...}).updateOne({ field: value }) instead of bulkOp.find({...}).updateOne({ $set: { field: value } }). The guard is !hasAtomicOperators(updateDocument, this.bulkOperation.bsonOptions) at src/bulk/common.ts:735.
Common situations: Developers copy-paste a replaceOne-style document into updateOne, or come from a SQL background and try to set fields directly. Also happens when a variable that was supposed to hold {$set: {...}} is reassigned to a plain object, or when building the update dynamically and the $set key is dropped by a spread bug.
Related errors
- Replacement document must not use atomic operators
- Update document requires atomic operators
- Update document requires atomic operators
- Argument "operations" must be an array of documents
- Argument "update" must be an object
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/b9f0852e51f2fb25.
Report an issue: GitHub.
Appendix: 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 dce7939f86)