mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Update document requires atomic operators
Error message
Update document requires atomic operators
What it means
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.
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.
Example fix
// before
await collection.findOneAndUpdate({ _id: id }, { status: 'done' });
// after
await collection.findOneAndUpdate({ _id: id }, { $set: { status: 'done' } }); Defensive patterns
Strategy: validation
Validate before calling
function hasAtomicOperators(doc: Record<string, unknown>): boolean {
const keys = Object.keys(doc);
return keys.length > 0 && keys[0].startsWith('$');
}
if (!hasAtomicOperators(update)) {
throw new TypeError('update must contain atomic operators like $set; for full replace use findOneAndReplace');
}
await collection.findOneAndUpdate(filter, update); Type guard
function isUpdateDoc(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v)
&& Object.keys(v).some(k => k.startsWith('$'));
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Confusing update (operators) with replacement (full document); omitting the $set wrapper; passing a full document intended for replaceOne.
Related errors
- Argument "update" must be an object
- Update document requires atomic operators
- Replacement document must not contain atomic operators
- Replacement document must not contain atomic operators
- Update document requires atomic operators
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/0b5654b5e3f68fa1.
Report an issue: GitHub.
Appendix: source
Thrown at src/operations/find_and_modify.ts:278
override options: FindOneAndUpdateOptions;
private update: Document;
constructor(
collection: Collection,
filter: Document,
update: Document,
options: FindOneAndUpdateOptions
) {
if (filter == null || typeof filter !== 'object') {
throw new MongoInvalidArgumentError('Argument "filter" must be an object');
}
if (update == null || typeof update !== 'object') {
throw new MongoInvalidArgumentError('Argument "update" must be an object');
}
if (!hasAtomicOperators(update, options)) {
throw new MongoInvalidArgumentError('Update document requires atomic operators');
}
super(collection, filter, options);
this.update = update;
this.options = options;
}
override buildCommandDocument(
connection: Connection,
session?: ClientSession
): Document & FindAndModifyCmdBase {
const document = super.buildCommandDocument(connection, session);
document.update = this.update;
configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
if (this.options.arrayFilters) {
document.arrayFilters = this.options.arrayFilters;
}View on GitHub (pinned to dce7939f86)