mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Replacement document must not contain atomic operators
Error message
Replacement document must not contain atomic operators
What it means
Thrown by ReplaceOneOperation's constructor when the replacement argument passed to collection.replaceOne() DOES contain atomic operators. replaceOne performs a full-document replacement and must not use $set/$inc/etc.; the replacement is a plain document with the new field values. This is the inverse check from updateOne. MongoInvalidArgumentError.
Source
Thrown at src/operations/update.ts:235
upsert?: boolean;
/** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */
let?: Document;
/** Specifies the sort order for the documents matched by the filter. */
sort?: Sort;
}
/** @internal */
export class ReplaceOneOperation extends UpdateOperation {
constructor(
ns: MongoDBCollectionNamespace,
filter: Document,
replacement: Document,
options: ReplaceOptions
) {
super(ns, [makeUpdateStatement(filter, replacement, { ...options, multi: false })], options);
if (hasAtomicOperators(replacement)) {
throw new MongoInvalidArgumentError('Replacement document must not contain atomic operators');
}
}
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): UpdateResult {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null) return res;
if (res.code) throw new MongoServerError(res);
if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);
return {
acknowledged: this.writeConcern?.w !== 0,
modifiedCount: res.nModified ?? res.n,
upsertedId:
Array.isArray(res.upserted) && res.upserted.length > 0 ? res.upserted[0]._id : null,View on GitHub (pinned to 3366c21a63)
Solutions
- Remove $ operators: pass the full target document, e.g. replaceOne(filter, { name: 'x', status: 1 }).
- If you actually want partial mutation with operators, use collection.updateOne() instead of replaceOne().
- Remember: replaceOne = whole document; updateOne = operators (or pipeline).
- Audit shared write-helper code that branches between the two.
Example fix
// before
await collection.replaceOne({ _id: 1 }, { $set: { name: 'x' } });
// after - choose one:
await collection.replaceOne({ _id: 1 }, { name: 'x' }); // full replace
// or
await collection.updateOne({ _id: 1 }, { $set: { name: 'x' } }); // partial update Defensive patterns
Strategy: validation
Validate before calling
function isReplacementDoc(doc) {
return doc != null && typeof doc === 'object' && !Array.isArray(doc) &&
!Object.keys(doc).some(k => k.startsWith('$'));
}
if (!isReplacementDoc(replacement)) throw new Error('replaceOne replacement must not use $ operators');
await collection.replaceOne(filter, replacement); Type guard
function isReplacementDoc(doc): doc is Record<string, unknown> {
return doc != null && typeof doc === 'object' && !Array.isArray(doc) &&
!Object.keys(doc).some(k => k.startsWith('$'));
} Prevention
- Keep replaceOne and updateOne code paths separate; don't share operator-tainted objects.
- Remember replaceOne = whole plain document.
- Review any generic 'write' helper that picks the method dynamically.
When it happens
Trigger: collection.replaceOne(filter, { $set: { ... } }) - the caller used replacement semantics but supplied update-operator syntax. Also happens when copy-pasting an updateOne call and only changing the method name.
Common situations: Renaming updateOne to replaceOne without removing the operators; mixing up the two operations' contracts; building a generic helper that assumes operators are always wanted.
Related errors
- Update document requires atomic operators
- Replacement document must not use atomic operators
- Update document requires atomic operators
- Update document requires atomic operators
- Selector must be a valid JavaScript object
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/449923bb9cf1f6f1.json.
Report an issue: GitHub.