mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Operation must be an object with an operation key
Error message
Operation must be an object with an operation key
What it means
Thrown as MongoInvalidArgumentError by BulkOperationBase.raw() (src/bulk/common.ts:1071) when the operation argument is null, undefined, or not an object. raw() dispatches on which operation key (insertOne/updateOne/etc.) is present, so it requires a non-null object containing at least one recognized operation key.
Solutions
- Inspect the operations array and ensure every element is a non-null object with exactly one of the recognized keys (insertOne, updateOne, updateMany, replaceOne, deleteOne, deleteMany).
- Filter out falsy entries before calling bulkWrite: ops.filter(Boolean).
- If a variable holds the inner payload, wrap it: ops.push({ insertOne: { document: doc } }).
Example fix
// before
await collection.bulkWrite([
undefined,
{ insertOne: { document: { a: 1 } } }
]);
// after
await collection.bulkWrite(
[
undefined,
{ insertOne: { document: { a: 1 } } }
].filter((op): op is NonNullable<typeof op> => op != null)
); Defensive patterns
Strategy: type-guard
Validate before calling
function isBulkOpObject(op: unknown): op is Record<string, unknown> {
return op != null && typeof op === 'object' && !Array.isArray(op);
}
const cleaned = ops.filter(isBulkOpObject);
if (cleaned.length !== ops.length) {
throw new Error('one or more bulk operations were null/non-object');
}
await coll.bulkWrite(cleaned); Type guard
function isBulkOp(op: unknown): op is Record<string, unknown> {
return op != null && typeof op === 'object' && !Array.isArray(op);
} Try / catch
try {
await coll.bulkWrite(ops);
} catch (e) {
if (e instanceof MongoInvalidArgumentError && /must be an object/.test(e.message)) {
await coll.bulkWrite(ops.filter((o): o is NonNullable<typeof o> => o != null && typeof o === 'object'));
} else throw e;
} Prevention
- Filter null/undefined entries out of the ops array before bulkWrite.
- Type the ops array as NonNullable<...>[] to surface holes at compile time.
- Validate at API boundaries: reject primitives/arrays in the ops list.
- Wrap inner payloads as { insertOne: { document: doc } } rather than passing the inner payload directly.
When it happens
Trigger: Calling collection.bulkWrite(ops) (which calls raw() per op) where one of the entries in the ops array is null, undefined, a primitive, or an array. Guarded by `if (op == null || typeof op !== 'object')` at src/bulk/common.ts:1070.
Common situations: A .map() that returns undefined for some elements, a filtered list that left a hole, JSON.parse of malformed input producing nulls, or accidentally passing the inner payload (e.g. op.insertOne) instead of the wrapper object { insertOne: ... }.
Related errors
- Argument "operations" must be an array of documents
- Operation passed in cannot be an Array
- Raw operations are not allowed
- Argument "docs" must be an array of documents
- Argument "pipeline" must be an array of aggregation stages
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/66d5d9b5449f035e.
Report an issue: GitHub.
Appendix: source
Thrown at src/bulk/common.ts:1071
* ```
*/
find(selector: Document): FindOperators {
if (!selector) {
throw new MongoInvalidArgumentError('Bulk find operation must specify a selector');
}
// Save a current selector
this.s.currentOp = {
selector: selector
};
return new FindOperators(this);
}
/** Specifies a raw operation to perform in the bulk write. */
raw(op: AnyBulkWriteOperation): this {
if (op == null || typeof op !== 'object') {
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');View on GitHub (pinned to dce7939f86)