{"record":{"id":"758dbd172b071d97","repo":"Automattic/mongoose","slug":"bulkwrite-failed-with-validationerrors-length-m","errorCode":null,"errorMessage":"bulkWrite failed with ${validationErrors.length} Mongoose validation errors: ${preview}","messagePattern":"bulkWrite failed with (.+?) Mongoose validation errors: (.+?)","errorType":"exception","errorClass":"MongooseBulkWriteError","httpStatus":null,"severity":"error","filePath":"lib/connection.js","lineNumber":560,"sourceCode":"          )\n        );\n      } else {\n        validOps.push({ ...op, namespace: Model.namespace() });\n        validOpIndexes.push(i);\n      }\n    }\n\n    if (asyncValidations.length > 0) {\n      await Promise.all(asyncValidations);\n    }\n\n    validationErrors = validationErrors.\n      sort((v1, v2) => v1.index - v2.index).\n      map(v => v.error);\n\n    if (validOps.length === 0) {\n      if (options.throwOnValidationError && validationErrors.length) {\n        throw new MongooseBulkWriteError(\n          validationErrors,\n          results,\n          res,\n          'bulkWrite'\n        );\n      }\n      const BulkWriteResult = this.base.driver.get().BulkWriteResult;\n      const res = new BulkWriteResult(getDefaultBulkwriteResult(), false);\n      return decorateBulkWriteResult(res, validationErrors, results);\n    }\n\n    let error;\n    [res, error] = await this.client.bulkWrite(validOps, options).\n      then(res => ([res, null])).\n      catch(err => ([null, err]));\n\n    for (let i = 0; i < validOpIndexes.length; ++i) {\n      results[validOpIndexes[i]] = null;","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/connection.js#L542-L578","documentation":"Connection.prototype.bulkWrite() validates every op ({ model, name, document, ... }) against the model's schema before sending anything to MongoDB. With { ordered: false } it collects per-op failures (schema validation, unregistered model name, unrecognized op name) into validationErrors; normally invalid ops are skipped and reported on the result, but with options.throwOnValidationError: true Mongoose throws a MongooseBulkWriteError instead. This throw site (lib/connection.js:560) fires only when every op in the batch failed validation, so validOps is empty and nothing was sent to the server.","triggerScenarios":"await conn.bulkWrite([{ model: 'Test', name: 'insertOne', document: { /* missing required field */ } }], { ordered: false, throwOnValidationError: true }) where all documents violate schema rules (required, enum, match, custom validators), or every op references an unregistered model name or unrecognized op name.","commonSituations":"Bulk import / ETL jobs feeding unvalidated data; a schema tightened (new required field or enum) without cleaning historical inputs; opting into all-or-nothing semantics with throwOnValidationError.","solutions":["Catch the error and inspect err.validationErrors and err.results to see exactly which ops failed and why, then fix those documents","Pre-validate each document before batching: const vErr = new conn.model(op.model)(op.document).validateSync()","Drop throwOnValidationError and handle partial success via res.mongoose.validationErrors","Relax or correct the schema rules if the strictness is unintended"],"exampleFix":"// before\nawait conn.bulkWrite(ops, { ordered: false, throwOnValidationError: true }); // throws when ALL ops invalid\n\n// after: pre-validate, split good/bad ops\nconst good = [], bad = [];\nfor (const op of ops) {\n  const Model = conn.model(op.model);\n  const vErr = new Model(op.document ?? {}).validateSync();\n  if (vErr) bad.push(op); else good.push(op);\n}\nif (good.length) await conn.bulkWrite(good, { ordered: false });","handlingStrategy":"try-catch","validationCode":"for (const op of ops) {\n  const Model = conn.model(op.model);\n  const vErr = new Model(op.document ?? {}).validateSync();\n  if (vErr) throw new Error(`op ${op.name} invalid: ${vErr.message}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const res = await conn.bulkWrite(ops, { ordered: false, throwOnValidationError: true });\n} catch (err) {\n  if (err?.name === 'MongooseBulkWriteError') {\n    // nothing was written (validOps was empty)\n    err.validationErrors.forEach(v => console.error(v.message));\n    return;\n  }\n  throw err;\n}","preventionTips":["Pre-validate every op's document with validateSync() before batching","Without throwOnValidationError, always inspect res.mongoose.validationErrors for skipped ops","Keep bulk imports on the same schema definitions as the app so validators cannot drift"],"tags":["bulk-write","schema-validation","ordered-false","throwonvalidationerror"],"backgroundTag":"schema-validation-failed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}