mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Replacement document must not use atomic operators
Error message
Replacement document must not use atomic operators
What it means
Thrown by FindOperators.replaceOne() when the replacement document contains atomic operators. A replacement document must be a plain object whose fields replace the existing document wholesale; mixing in $set/$inc etc. is illegal because the server would reject the command. hasAtomicOperators() returns true when the first key starts with '$'.
Source
Thrown at src/bulk/common.ts:749
}
/** 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,
makeUpdateStatement(currentOp.selector, replacement, { ...currentOp, multi: false })
);
}
/** Add a delete one operation to the bulk operation */
deleteOne(): BulkOperationBase {
const currentOp = buildCurrentOp(this.bulkOperation);
return this.bulkOperation.addToOperationsList(
BatchType.DELETE,
makeDeleteStatement(currentOp.selector, { ...currentOp, limit: 1 })
);
}
View on GitHub (pinned to 3366c21a63)
Solutions
- Strip the atomic operator and pass a plain replacement: { $set: { a: 1 } } -> { a: 1 }.
- If you actually want partial update semantics, switch to updateOne/updateMany instead of replaceOne.
Example fix
// before
bulk.find({ _id: 1 }).replaceOne({ $set: { name: 'alice' } });
// after
bulk.find({ _id: 1 }).replaceOne({ name: 'alice' }); Defensive patterns
Strategy: validation
Validate before calling
function isPlainReplacement(doc) {
return doc != null && typeof doc === 'object' &&
Object.keys(doc).every(k => k[0] !== '$');
} Type guard
function isReplacementDoc(doc) {
return (
doc != null &&
typeof doc === 'object' &&
!Array.isArray(doc) &&
(Object.keys(doc).length === 0 || Object.keys(doc)[0][0] !== '$')
);
} Try / catch
try {
bulk.find(filter).replaceOne(rep);
} catch (e) {
if (e instanceof MongoInvalidArgumentError && /must not use atomic/.test(e.message)) {
// strip $-wrapper or route to updateOne
}
throw e;
} Prevention
- Treat replaceOne and updateOne as semantically distinct; never share document builders between them.
- In code review, flag any $-prefixed key inside a replaceOne payload.
When it happens
Trigger: Calling bulk.find(filter).replaceOne({ $set: {...} }) or any replaceOne where the first key is a $-operator. Copy-pasting an update document into a replaceOne call site.
Common situations: Refactoring between updateOne and replaceOne without adjusting the document shape; building documents generically and routing them to the wrong method.
Related errors
- Update document requires atomic operators
- Bulk find operation must specify a selector
- Operation must be an object with an operation key
- Raw operations are not allowed
- Invalid BulkOperation, Batch cannot be empty
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/c63ddc841faa3019.json.
Report an issue: GitHub.