mongodb/node-mongodb-native · error · MongoAPIError

Client bulk write replace models must not contain atomic mod

Error message

Client bulk write replace models must not contain atomic modifiers (start with $) and must not be empty.

What it means

Thrown when building a replaceOne model if the replacement document is empty or contains keys starting with '$'. Per spec, replaceOne MUST be a full replacement document (no atomic operators); if you want $ operators use updateOne/updateMany. Classified as MongoAPIError.

Source

Thrown at src/operations/client_bulk_write/command_builder.ts:440

  updateMods: WithoutId<Document>;
  hint?: Hint;
  upsert?: boolean;
  collation?: CollationOptions;
  sort?: SortForCmd;
}

/**
 * Build the replace one operation.
 * @param model - The replace one model.
 * @param index - The namespace index.
 * @returns the operation.
 */
export const buildReplaceOneOperation = (
  model: ClientReplaceOneModel<Document>,
  index: number
): ClientReplaceOneOperation => {
  if (hasAtomicOperators(model.replacement)) {
    throw new MongoAPIError(
      'Client bulk write replace models must not contain atomic modifiers (start with $) and must not be empty.'
    );
  }

  const document: ClientReplaceOneOperation = {
    update: index,
    multi: false,
    filter: model.filter,
    updateMods: model.replacement
  };
  if (model.hint) {
    document.hint = model.hint;
  }
  if (model.upsert) {
    document.upsert = model.upsert;
  }
  if (model.collation) {
    document.collation = model.collation;

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Provide a non-empty replacement document without any '$'-prefixed keys.
  2. If you need atomic operators, switch the model name to updateOne/updateMany.
  3. Validate: assert Object.keys(replacement).length > 0 && !Object.keys(replacement)[0].startsWith('$').

Example fix

// before
await client.bulkWrite([{
  namespace: 'db.coll',
  name: 'replaceOne',
  filter: { _id: 1 },
  replacement: { $set: { a: 1 } } // wrong
}]);

// after
await client.bulkWrite([{
  namespace: 'db.coll',
  name: 'replaceOne',
  filter: { _id: 1 },
  replacement: { a: 1 }
}]);
Defensive patterns

Strategy: validation

Validate before calling

function isValidReplacement(doc) {
  const keys = Object.keys(doc);
  return keys.length > 0 && keys.every(k => !k.startsWith('$'));
}

Type guard

function isPlainReplacement(v): boolean {
  return v != null && typeof v === 'object' && Object.keys(v).every(k => !k.startsWith('$'));
}

Prevention

When it happens

Trigger: Passing client.bulkWrite() a replaceOne model whose replacement is { $set: {...} } or {}. Mixing up updateOne and replaceOne semantics.

Common situations: Switching from updateOne to replaceOne but leaving $set; passing an empty replacement built from a failed mapping.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/70d6fb31c2b63700.json. Report an issue: GitHub.