Automattic/mongoose · error · MongooseBulkWriteError

bulkWrite failed with ${validationErrors.length} Mongoose va

Error message

bulkWrite failed with ${validationErrors.length} Mongoose validation errors: ${preview}

What it means

Mongoose casts bulkWrite operations against the schema (insertOne/replaceOne documents, updateOne filters/updates) and collects failures as validationErrors with their op indexes. When zero operations are valid and options.throwOnValidationError is true, Mongoose throws MongooseBulkWriteError with this message before any write is sent; without the option it returns a synthesized BulkWriteResult decorated with the validation errors (check res.mongoose?.validationErrors).

Source

Thrown at lib/model.js:3526

            }
            resolve();
          });
        });
      }));
      validOpIndexes = validOpIndexes.filter(index => index != null);
    } else {
      validOpIndexes = ops.map((op, i) => i);
    }

    validationErrors = validationErrors.
      sort((v1, v2) => v1.index - v2.index).
      map(v => v.error);

    const validOps = validOpIndexes.sort((a, b) => a - b).map(index => ops[index]);

    if (validOps.length === 0) {
      if (options.throwOnValidationError && validationErrors.length) {
        throw new MongooseBulkWriteError(
          validationErrors,
          results,
          res,
          'bulkWrite'
        );
      }
      const BulkWriteResult = this.base.driver.get().BulkWriteResult;
      const bulkWriteResult = new BulkWriteResult(getDefaultBulkwriteResult(), false);
      bulkWriteResult.result = getDefaultBulkwriteResult();
      decorateBulkWriteResult(bulkWriteResult, validationErrors, results);
      return bulkWriteResult;
    }

    let error;
    [res, error] = await this.$__collection.bulkWrite(validOps, options).
      then(res => ([res, null])).
      catch(error => ([null, error]));

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Read err.validationErrors: entries carry the failing op's index and the underlying ValidatorError/CastError; fix those ops or the data producing them
  2. Pre-validate documents with new Model(d).validateSync() before building ops, and drop/report invalid ones
  3. If skipping invalid ops is desired, omit throwOnValidationError and inspect res.mongoose.validationErrors on the returned result instead
  4. Verify the ops match the current schema after adding required fields or stricter enums

Example fix

// before
const ops = rows.map(r => ({ insertOne: { document: r } }));
await User.bulkWrite(ops, { throwOnValidationError: true }); // every op invalid -> throws

// after
const ops = rows
  .map(r => ({ doc: new User(r), err: new User(r).validateSync() }))
  .filter(x => !x.err)
  .map(x => ({ insertOne: { document: x.doc } }));
await User.bulkWrite(ops);
Defensive patterns

Strategy: validation

Validate before calling

function buildValidatedOps(Model, rows) {
  const ops = [];
  const invalid = [];
  rows.forEach((r, i) => {
    const doc = new Model(r);
    const err = doc.validateSync();
    if (err) invalid.push({ index: i, err });
    else ops.push({ insertOne: { document: doc } });
  });
  if (ops.length === 0) throw new Error('no valid ops', { cause: invalid[0]?.err });
  return { ops, invalid };
}

Try / catch

try {
  const res = await Model.bulkWrite(ops, { throwOnValidationError: true });
} catch (err) {
  if (err.name === 'MongooseBulkWriteError') {
    for (const v of err.validationErrors) { /* v.index = failing op, v.message = why */ }
  } else throw err;
}

Prevention

When it happens

Trigger: await Model.bulkWrite([{ insertOne: { document: { /* missing required */ } } }, ...], { throwOnValidationError: true }) where every op fails casting/validation.

Common situations: Bulk ETL jobs feeding unvalidated external data into insertOne/replaceOne/updateOne ops; enabling throwOnValidationError on a pipeline whose upstream schema changed (new required field) so all ops now fail.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21). Data as JSON: /api/errors/7ff1cc68a60333a5. Report an issue: GitHub.