mongodb/node-mongodb-native · error · MongoAPIError
Client bulk write update models must only contain atomic mod
Error message
Client bulk write update models must only contain atomic modifiers (start with $) and must not be empty.
What it means
Thrown by validateUpdate() when an updateOne/updateMany model's update document is empty or its first key does not start with '$'. Per the cross-driver spec, update operations in client bulk writes MUST use atomic operators ($set, $inc, etc.); replacement-style documents are not allowed here (use replaceOne instead). Classified as MongoAPIError.
Source
Thrown at src/operations/client_bulk_write/command_builder.ts:373
* @param model - The update many model.
* @param index - The namespace index.
* @returns the operation.
*/
export const buildUpdateManyOperation = (
model: ClientUpdateManyModel<Document>,
index: number,
options: BSONSerializeOptions
): ClientUpdateOperation => {
return createUpdateOperation(model, index, true, options);
};
/**
* Validate the update document.
* @param update - The update document.
*/
function validateUpdate(update: Document, options: BSONSerializeOptions) {
if (!hasAtomicOperators(update, options)) {
throw new MongoAPIError(
'Client bulk write update models must only contain atomic modifiers (start with $) and must not be empty.'
);
}
}
/**
* Creates a delete operation based on the parameters.
*/
function createUpdateOperation(
model: ClientUpdateOneModel<Document> | ClientUpdateManyModel<Document>,
index: number,
multi: boolean,
options: BSONSerializeOptions
): ClientUpdateOperation {
// Update documents provided in UpdateOne and UpdateMany write models are
// required only to contain atomic modifiers (i.e. keys that start with "$").
// Drivers MUST throw an error if an update document is empty or if the
// document's first key does not start with "$".View on GitHub (pinned to 3366c21a63)
Solutions
- Wrap the fields in $set: update: { $set: { field: value } }.
- Use a replaceOne model if you intend a full-document replacement.
- Validate before sending: assert model.update && Object.keys(model.update)[0]?.startsWith('$').
Example fix
// before
await client.bulkWrite([{
namespace: 'db.coll',
name: 'updateOne',
filter: { _id: 1 },
update: { status: 'done' } // no $ operator
}]);
// after
await client.bulkWrite([{
namespace: 'db.coll',
name: 'updateOne',
filter: { _id: 1 },
update: { $set: { status: 'done' } }
}]); Defensive patterns
Strategy: validation
Validate before calling
function isValidUpdate(update) {
const keys = Object.keys(update);
return keys.length > 0 && keys[0].startsWith('$');
} Type guard
function isAtomicUpdate(v): boolean {
return v != null && typeof v === 'object' && Object.keys(v).every(k => k.startsWith('$'));
} Prevention
- Always use $set/$inc etc. for updateOne/updateMany
- Use replaceOne for full-document replacement
- Validate the update has at least one $ key before sending
When it happens
Trigger: Passing client.bulkWrite() an updateOne/updateMany model whose update is { field: value } (no $ operator) or {} (empty). Accidentally using a replacement document where an atomic update was intended.
Common situations: Treating updateOne like replaceOne; building update dynamically and ending with an empty object; copy-paste from collection.updateOne that accepted full replacements in older patterns.
Related errors
- Update document requires atomic operators
- Client bulk write replace models must not contain atomic mod
- No client bulk write models were provided.
- Replacement document must not use atomic operators
- Bulk find operation must specify a selector
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/c7b4d995bb4e67ea.json.
Report an issue: GitHub.