mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Raw operations are not allowed

Error message

Raw operations are not allowed

What it means

Thrown as MongoInvalidArgumentError inside BulkOperationBase.raw() (src/bulk/common.ts:1089) when a replaceOne operation object contains a 'q' key. The 'q' field is part of the server-side wire-protocol update statement shape (q/u), not the user-facing API shape (filter/replacement); the driver forbids passing already-encoded 'raw' operations through the public bulkWrite path to keep the API contract clean.

Solutions

  1. Re-shape the operation to the user-facing form: { replaceOne: { filter: {...}, replacement: {...} } }.
  2. If you have wire-protocol ops from a log, map q -> filter and u -> replacement (for replace) before passing them in.
  3. Do not construct ops from generic { q, u } helpers; use the documented key names.

Example fix

// before
await coll.bulkWrite([
  { replaceOne: { q: { _id: 1 }, u: { name: 'Sam' } } }
]);

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

Strategy: validation

Validate before calling

function isUserFacingReplaceOne(op: any): boolean {
  return op && 'replaceOne' in op && !('q' in op.replaceOne) &&
    'filter' in op.replaceOne && 'replacement' in op.replaceOne;
}

if (!isUserFacingReplaceOne(op)) {
  throw new Error('replaceOne must use { filter, replacement }, not the wire { q, u } shape');
}

Type guard

type UserReplaceOne = { replaceOne: { filter: Record<string, unknown>; replacement: Record<string, unknown> } };

function isUserFacingReplaceOne(op: unknown): op is UserReplaceOne {
  if (op == null || typeof op !== 'object') return false;
  const r = (op as any).replaceOne;
  return r != null && typeof r === 'object' &&
    !('q' in r) && 'filter' in r && 'replacement' in r;
}

Try / catch

try {
  await coll.bulkWrite(ops);
} catch (e) {
  if (e instanceof MongoInvalidArgumentError && /Raw operations are not allowed/.test(e.message)) {
    // map wire shape q/u -> filter/replacement, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Passing { replaceOne: { q: {...}, u: {...} } } to bulkOp.raw(...) (or collection.bulkWrite). The check is `if ('q' in op.replaceOne)` at src/bulk/common.ts:1088.

Common situations: Re-using wire-protocol payloads captured from a logger/proxy, building ops from generic { q, u } factories, or porting code that previously manipulated the low-level op format. Rarely accidental; usually a structural mismatch between captured and user-facing op shapes.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/3a81aef9d1b278f1. Report an issue: GitHub.

Appendix: source

Thrown at src/bulk/common.ts:1089

      throw new MongoInvalidArgumentError('Operation must be an object with an operation key');
    }
    if ('insertOne' in op) {
      const forceServerObjectId = this.shouldForceServerObjectId();
      const document =
        op.insertOne && op.insertOne.document == null
          ? // TODO(NODE-6003): remove support for omitting the `documents` subdocument in bulk inserts
            (op.insertOne as Document)
          : op.insertOne.document;

      maybeAddIdToDocuments(this.collection, document, { forceServerObjectId });

      return this.addToOperationsList(BatchType.INSERT, document);
    }

    if ('replaceOne' in op || 'updateOne' in op || 'updateMany' in op) {
      if ('replaceOne' in op) {
        if ('q' in op.replaceOne) {
          throw new MongoInvalidArgumentError('Raw operations are not allowed');
        }
        const updateStatement = makeUpdateStatement(
          op.replaceOne.filter,
          op.replaceOne.replacement,
          { ...op.replaceOne, multi: false }
        );
        if (hasAtomicOperators(updateStatement.u)) {
          throw new MongoInvalidArgumentError('Replacement document must not use atomic operators');
        }
        return this.addToOperationsList(BatchType.UPDATE, updateStatement);
      }

      if ('updateOne' in op) {
        if ('q' in op.updateOne) {
          throw new MongoInvalidArgumentError('Raw operations are not allowed');
        }
        const updateStatement = makeUpdateStatement(op.updateOne.filter, op.updateOne.update, {
          ...op.updateOne,

View on GitHub (pinned to dce7939f86)