mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Argument "replacement" must be an object

Error message

Argument "replacement" must be an object

What it means

FindOneAndReplaceOperation's constructor (src/operations/find_and_modify.ts:236) requires the `replacement` argument to be a non-null object. The replacement is a full document that substitutes the matched document, so it must be a plain document without update operators. Passing null/undefined/primitive throws a MongoInvalidArgumentError.

Source

Thrown at src/operations/find_and_modify.ts:236

    return document;
  }
}

/** @internal */
export class FindOneAndReplaceOperation extends FindAndModifyOperation {
  private replacement: Document;
  constructor(
    collection: Collection,
    filter: Document,
    replacement: Document,
    options: FindOneAndReplaceOptions
  ) {
    if (filter == null || typeof filter !== 'object') {
      throw new MongoInvalidArgumentError('Argument "filter" must be an object');
    }

    if (replacement == null || typeof replacement !== 'object') {
      throw new MongoInvalidArgumentError('Argument "replacement" must be an object');
    }

    if (hasAtomicOperators(replacement)) {
      throw new MongoInvalidArgumentError('Replacement document must not contain atomic operators');
    }

    super(collection, filter, options);
    this.replacement = replacement;
  }

  override buildCommandDocument(
    connection: Connection,
    session?: ClientSession
  ): Document & FindAndModifyCmdBase {
    const document = super.buildCommandDocument(connection, session);
    document.update = this.replacement;
    configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
    return document;

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Pass a full replacement document: collection.findOneAndReplace(filter, { name: 'new', qty: 5 }).
  2. If you need atomic operators like $set, use findOneAndUpdate instead of findOneAndReplace.
  3. Ensure the replacement variable is a defined object before the call.

Example fix

// before
await collection.findOneAndReplace({ _id }, { $set: { name: 'x' } }); // wrong API

// after
// for a full replacement:
await collection.findOneAndReplace({ _id }, { name: 'x', qty: 0 });
// or use findOneAndUpdate for atomic operators:
await collection.findOneAndUpdate({ _id }, { $set: { name: 'x' } });
Defensive patterns

Strategy: validation

Validate before calling

function assertReplacement(doc: unknown): asserts doc is Record<string, unknown> {
  if (doc == null || typeof doc !== 'object' || Array.isArray(doc)) {
    throw new TypeError('findOneAndReplace: replacement must be a plain object');
  }
}

Type guard

const isValidReplacement = (d: unknown): d is Record<string, unknown> =>
  d != null && typeof d === 'object' && !Array.isArray(d);

Prevention

When it happens

Trigger: Calling collection.findOneAndReplace(filter, null), collection.findOneAndReplace(filter, undefined), or passing a non-object as replacement.

Common situations: Omitting the replacement argument, passing a partial update with $set operators (which belongs in findOneAndUpdate), or a variable that resolved to undefined.

Related errors


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