Automattic/mongoose · error · MongooseError

Model.create() no longer accepts a callback

Error message

Model.create() no longer accepts a callback

What it means

Model.create() became an async function that only accepts documents plus an options object; Mongoose 7 removed callback support. This first guard throws when options itself is a function or the third argument is a function, i.e. the array form Model.create([docs], callback) or Model.create(doc, callback) where the callback lands in the options parameter. Because create() is async, the throw surfaces as a rejected promise rather than a synchronous throw.

Source

Thrown at lib/model.js:2692

 *     await Character.create([{ name: 'Will Riker' }, { name: 'Geordi LaForge' }]);
 *
 *     // Create a new character within a transaction. Note that you **must**
 *     // pass an array as the first parameter to `create()` if you want to
 *     // specify options.
 *     await Character.create([{ name: 'Jean-Luc Picard' }], { session });
 *
 * @param {Array|object} docs Documents to insert, as a spread or array
 * @param {object} [options] Options passed down to `save()`. To specify `options`, `docs` **must** be an array, not a spread. See [Model.save](https://mongoosejs.com/docs/api/model.html#Model.prototype.save()) for available options.
 * @param {boolean} [options.ordered] saves the docs in series rather than parallel.
 * @param {boolean} [options.aggregateErrors] Aggregate Errors instead of throwing the first one that occurs. Default: false
 * @return {Promise}
 * @api public
 */

Model.create = async function create(doc, options) {
  if (typeof options === 'function' ||
      typeof arguments[2] === 'function') {
    throw new MongooseError('Model.create() no longer accepts a callback');
  }

  _checkContext(this, 'create');

  let args;
  const discriminatorKey = this.schema.options.discriminatorKey;

  if (Array.isArray(doc)) {
    args = doc;
    options = options != null && typeof options === 'object' ? options : {};
  } else {
    const last = arguments[arguments.length - 1];
    options = {};
    const hasCallback = typeof last === 'function' ||
      typeof options === 'function' ||
      typeof arguments[2] === 'function';
    if (hasCallback) {
      throw new MongooseError('Model.create() no longer accepts a callback');

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Use await: const docs = await Model.create([d1, d2]); or const doc = await Model.create(d1); with try/catch
  2. Remember options must be an object and only allowed when docs is an array: await Model.create([d1, d2], { session, ordered: true })
  3. Audit the codebase for create(..., function/arrow) patterns during the Mongoose 7 migration
  4. Pin mongoose@6 as a temporary stopgap
  5. Use TypeScript: the create() signature no longer accepts a callback, so tsc flags it

Example fix

// before
User.create([{ name: 'a' }], (err, docs) => { ... });

// after
const docs = await User.create([{ name: 'a' }]);
Defensive patterns

Strategy: validation

Validate before calling

function createSafe(Model, docs, options) {
  if (typeof options === 'function') throw new TypeError('create(): pass options object, not a callback');
  if (arguments.length > 3) throw new TypeError('create(): extra argument');
  return Model.create(docs, options);
}

Try / catch

try {
  const docs = await Model.create(list, { session, ordered: true });
} catch (err) {
  if (/no longer accepts a callback/.test(err.message)) { /* legacy call site: switch to await */ }
  else throw err;
}

Prevention

When it happens

Trigger: Calling Model.create([d1, d2], cb) (array plus callback), or Model.create(doc, cb) where cb occupies the options slot (arguments[1]), or passing any function as arguments[2].

Common situations: Mongoose 6 to 7/8 upgrades; bulk-seed scripts written with callbacks; generic factory helpers that append a done() function to create() calls.

Related errors


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