mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Operation passed in cannot be an Array

Error message

Operation passed in cannot be an Array

What it means

Thrown as MongoInvalidArgumentError by OrderedBulkOperation.addToOperationsList() (src/bulk/ordered.ts:88) when the document passed to addToOperationsList is a JavaScript Array. addToOperationsList expects a single BSON document (or update/delete statement); passing an array is a structural mistake because the bulk op processes one op at a time and has already serialized the value as if it were a document.

Solutions

  1. Ensure the value passed for a single op is a plain object, not an array — iterate and add each element as its own operation if you have many.
  2. If you have an array of documents to insert, call bulk.insert(doc) per element rather than bulk.insert(docArray).
  3. Audit any custom wrapper that forwards payloads into addToOperationsList to confirm it passes documents one at a time.

Example fix

// before: passing an array where a single document is expected
for (const doc of docs) {
  // some custom path ends up calling addToOperationsList(BatchType.INSERT, docs)
}

// after: add each document individually
for (const doc of docs) {
  bulk.insert(doc); // one document per call
}
Defensive patterns

Strategy: type-guard

Validate before calling

function isSingleDocument(doc: unknown): boolean {
  return doc != null && typeof doc === 'object' && !Array.isArray(doc);
}

for (const op of ops) {
  const doc = (op as any).insertOne?.document;
  if (doc != null && !isSingleDocument(doc)) {
    throw new Error('expected a single document, got an array');
  }
}

Type guard

function isSingleDocument(doc: unknown): doc is Record<string, unknown> {
  return doc != null && typeof doc === 'object' && !Array.isArray(doc);
}

Try / catch

try {
  await bulk.execute();
} catch (e) {
  if (e instanceof MongoInvalidArgumentError && /cannot be an Array/.test(e.message)) {
    // flatten any array-valued document into one insert per element, then re-execute
  } else throw e;
}

Prevention

When it happens

Trigger: An internal/builder caller (or a user reaching addToOperationsList via raw() with a malformed insert) passes an Array where a Document is expected. Guarded by `if (Array.isArray(document))` at src/bulk/ordered.ts:87.

Common situations: Mostly an internal-driver or advanced-usage error; can surface if a user constructs an operation whose `document`/`update`/`replacement` field is an array where the API expects a single object, or when wrapping the driver in a custom layer that forwards arrays. Very rare through the standard bulkWrite() path.

Related errors


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

Appendix: source

Thrown at src/bulk/ordered.ts:88

      // Create a new batch
      this.s.currentBatch = new Batch(batchType, this.s.currentIndex);

      // Reset the current size trackers
      this.s.currentBatchSize = 0;
      this.s.currentBatchSizeBytes = 0;
    }

    if (batchType === BatchType.INSERT) {
      this.s.bulkResult.insertedIds.push({
        index: this.s.currentIndex,
        _id: (document as Document)._id
      });
    }

    // We have an array of documents
    if (Array.isArray(document)) {
      throw new MongoInvalidArgumentError('Operation passed in cannot be an Array');
    }

    this.s.currentBatch.originalIndexes.push(this.s.currentIndex);
    this.s.currentBatch.operations.push(document);
    if (buffer != null) this.s.currentBatch.serializedOperations.push(buffer);
    this.s.currentBatchSize += 1;
    this.s.currentBatchSizeBytes += maxKeySize + bsonSize;
    this.s.currentIndex += 1;
    return this;
  }
}

View on GitHub (pinned to dce7939f86)