{"record":{"id":"1b1d982b67c1a503","repo":"Automattic/mongoose","slug":"insertmany-failed-with-validationerrors-length","errorCode":null,"errorMessage":"insertMany failed with ${validationErrors.length} Mongoose validation errors: ${preview}","messagePattern":"insertMany failed with (.+?) Mongoose validation errors: (.+?)","errorType":"exception","errorClass":"MongooseBulkWriteError","httpStatus":null,"severity":"error","filePath":"lib/model.js","lineNumber":3152,"sourceCode":"      doc.initializeTimestamps(timestamps);\n    }\n    docObjects.push(doc.$__hasOnlyPrimitiveValues() ? doc.$__toObjectShallow() : doc.toObject(internalToObjectOptions));\n  }\n\n  // Make sure validation errors are in the same order as the\n  // original documents, so if both doc1 and doc2 both fail validation,\n  // `Model.insertMany([doc1, doc2])` will always have doc1's validation\n  // error before doc2's. Re: gh-12791.\n  if (validationErrors.length > 0 && ordered === false) {\n    validationErrors.sort((err1, err2) => {\n      return err1.index - err2.index;\n    });\n  }\n\n  // Quickly escape while there aren't any valid docAttributes\n  if (docAttributes.length === 0) {\n    if (throwOnValidationError) {\n      throw new MongooseBulkWriteError(\n        validationErrors,\n        results,\n        null,\n        'insertMany'\n      );\n    }\n    if (rawResult) {\n      const res = {\n        acknowledged: true,\n        insertedCount: 0,\n        insertedIds: {}\n      };\n      decorateBulkWriteResult(res, validationErrors, validationErrors);\n      return res;\n    }\n    return [];\n  }\n","sourceCodeStart":3134,"sourceCodeEnd":3170,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/model.js#L3134-L3170","documentation":"During insertMany, documents that fail schema validation are separated into validationErrors and valid ones into docAttributes. When zero documents pass validation and options.throwOnValidationError is true (requires ordered: false), Mongoose throws MongooseBulkWriteError with this message, carrying .validationErrors (each with the failing document's index and ValidatorError details). Without throwOnValidationError, insertMany silently returns [] (or an acknowledged result with insertedCount 0), which is why the option exists.","triggerScenarios":"await Model.insertMany(docs, { ordered: false, throwOnValidationError: true }) where every document fails validation (missing required field, enum mismatch, custom validator rejection).","commonSituations":"Bulk imports of CSV/JSON data where required fields are absent or values fail enum/custom validators; enabling throwOnValidationError to stop silently dropping invalid rows and then hitting fully invalid batches.","solutions":["Inspect err.validationErrors: each entry has .index (position in the input array) and .message identifying the failed path and rule; fix the source data or schema accordingly","Pre-validate the batch before insertMany: const errs = docs.map(d => new Model(d).validateSync()); and filter/handle invalid entries","If skipping invalid docs is acceptable, omit throwOnValidationError (default false) and check the returned array length / insertedCount","Clean the data at ingestion: coerce types, fill defaults, validate enum values before the bulk write"],"exampleFix":"// before\nawait User.insertMany(rows, { ordered: false, throwOnValidationError: true }); // all rows invalid -> throws\n\n// after\nconst valid = [];\nconst invalid = [];\nfor (const row of rows) {\n  const doc = new User(row);\n  const err = doc.validateSync();\n  (err ? invalid : valid).push(err ? { row, err } : doc);\n}\nawait User.insertMany(valid, { ordered: false });\n// report `invalid` to the caller","handlingStrategy":"validation","validationCode":"function prevalidateBatch(Model, docs) {\n  return docs.reduce(({ valid, invalid }, d, i) => {\n    const err = new Model(d).validateSync();\n    if (err) invalid.push({ index: i, err }); else valid.push(d);\n    return { valid, invalid };\n  }, { valid: [], invalid: [] });\n}\nconst { valid, invalid } = prevalidateBatch(Model, docs);\nif (valid.length === 0) throw new Error('entire batch invalid', { cause: invalid[0].err });\nawait Model.insertMany(valid, { ordered: false });","typeGuard":null,"tryCatchPattern":"try {\n  await Model.insertMany(docs, { ordered: false, throwOnValidationError: true });\n} catch (err) {\n  if (err.name === 'MongooseBulkWriteError') {\n    for (const v of err.validationErrors) {\n      // v.index -> position in input, v.message -> failed path + rule\n    }\n  } else throw err;\n}","preventionTips":["Dry-run batches through validateSync() before insertMany when data quality is uncertain","Prefer throwOnValidationError: true with ordered: false over silent drops so bad rows are visible","Add schema-level integration tests that exercise the same validators as production payloads"],"tags":["mongoose","validation","insertmany","bulk","throwonvalidationerror"],"backgroundTag":"schema-validation-failed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}