mongodb/node-mongodb-native · error · MongoInvalidArgumentError
Argument "docs" must be an array of documents
Error message
Argument "docs" must be an array of documents
What it means
Thrown by Collection.insertMany() when the first argument is not an Array. The driver wraps each provided document into an { insertOne: { document } } bulk operation, so it must iterate the input; a non-iterable value cannot be processed. This is a MongoInvalidArgumentError raised before any network call. The TypeScript signature already requires ReadonlyArray<OptionalUnlessRequiredId<TSchema>>, so this signals a type-safety escape (any/unknown) or a runtime-only caller.
Source
Thrown at src/collection.ts:317
resolveOptions(this, options)
) as TODO_NODE_3286
);
}
/**
* Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
* one will be added to each of the documents missing it by the driver, mutating the document. This behavior
* can be overridden by setting the **forceServerObjectId** flag.
*
* @param docs - The documents to insert
* @param options - Optional settings for the command
*/
async insertMany(
docs: ReadonlyArray<OptionalUnlessRequiredId<TSchema>>,
options?: BulkWriteOptions
): Promise<InsertManyResult<TSchema>> {
if (!Array.isArray(docs)) {
throw new MongoInvalidArgumentError('Argument "docs" must be an array of documents');
}
options = resolveOptions(this, options ?? {});
const acknowledged = WriteConcern.fromOptions(options)?.w !== 0;
try {
const res = await this.bulkWrite(
docs.map(doc => ({ insertOne: { document: doc } })),
options
);
return {
acknowledged,
insertedCount: res.insertedCount,
insertedIds: res.insertedIds
};
} catch (err) {
if (err && err.message === 'Operation must be an object with an operation key') {
throw new MongoInvalidArgumentError(View on GitHub (pinned to 3366c21a63)
Solutions
- Wrap the value in an array at the call site: insertMany(Array.isArray(docs) ? docs : [docs]).
- If building the array dynamically, default it: await collection.insertMany(docs ?? []).
- Add an Array.isArray(docs) guard before calling insertMany and surface a clearer error to your caller.
- Enable strict TypeScript typing on the caller so the non-array value is caught at compile time.
Example fix
// before await collection.insertMany(req.body); // after await collection.insertMany(Array.isArray(req.body) ? req.body : [req.body]);
Defensive patterns
Strategy: type-guard
Validate before calling
function asInsertManyDocs<T>(docs: unknown): T[] {
if (!Array.isArray(docs)) {
throw new TypeError('insertMany requires an array');
}
return docs as T[];
}
// usage:
await collection.insertMany(asInsertManyDocs(maybeDocs)); Type guard
const isDocumentArray = (v: unknown): v is Record<string, unknown>[] => Array.isArray(v) && v.every(d => d != null && typeof d === 'object' && !Array.isArray(d));
Try / catch
try {
await collection.insertMany(docs);
} catch (e) {
if (e instanceof MongoInvalidArgumentError && /must be an array of documents/.test(e.message)) {
throw new TypeError('Expected an array of documents, got: ' + typeof docs);
}
throw e;
} Prevention
- Always type the variable you pass as ReadonlyArray<...>.
- Initialize dynamic arrays to [] and push, never assign undefined.
- Lint for awaiting promises before passing to insertMany.
When it happens
Trigger: Calling collection.insertMany(singleDoc) passing a single object instead of an array; passing undefined/null when the array is conditionally built; passing a Map, Set, or other iterable that is not an Array (Array.isArray returns false); passing a Promise that resolved to an array but was not awaited.
Common situations: JavaScript callers that forgot to wrap a single document in []; a value sourced from JSON.parse or an untyped API response fed directly in; refactoring from insertOne to insertMany without adjusting the call site; awaiting an async iterator's result incorrectly.
Related errors
- Collection.insertMany() cannot be called with an array that
- Argument "operations" must be an array of documents
- Argument "pipeline" must be an array of aggregation stages
- Update operations require that all atomic operators have def
- Option "keyAltNames" must be an array of strings, but was of
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/e0fb990ab93f3ccb.json.
Report an issue: GitHub.