mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Raw operations are not allowed

Error message

Raw operations are not allowed

What it means

Thrown by BulkOperationBase.raw() when a replaceOne operation uses the raw wire-protocol field 'q' (e.g. { replaceOne: { q: {...}, u: {...} } }). The driver only accepts the user-facing shape { filter, replacement }; raw server-side statement shapes are rejected to prevent ambiguity and double-encoding.

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 3366c21a63)

Solutions

  1. Rewrite the operation using the documented keys: { replaceOne: { filter: q, replacement: u } }.
  2. If you have raw statements, convert them with a mapper before passing to bulk.raw().

Example fix

// before
bulk.raw({ replaceOne: { q: { _id: 1 }, u: { name: 'a' } } });

// after
bulk.raw({ replaceOne: { filter: { _id: 1 }, replacement: { name: 'a' } } });
Defensive patterns

Strategy: validation

Validate before calling

function toUserReplaceOne(op) {
  if ('q' in op.replaceOne || 'u' in op.replaceOne) {
    return { replaceOne: { filter: op.replaceOne.q, replacement: op.replaceOne.u } };
  }
  return op;
}

Type guard

function isUserFacingReplaceOne(op) {
  return 'replaceOne' in op && !('q' in op.replaceOne);
}

Try / catch

try {
  bulk.raw(op);
} catch (e) {
  if (/Raw operations are not allowed/.test(e.message)) {
    op = normalizeOp(op); // map q/u -> filter/replacement
    bulk.raw(op);
  }
}

Prevention

When it happens

Trigger: Passing { replaceOne: { q: filter, u: replacement } } to bulk.raw(). Constructing operations from serialized server statements or log dumps that use q/u field names.

Common situations: Copying operation shapes from MongoDB profiler output, oplog entries, or older driver internals that expose the q/u keys.

Related errors


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