Automattic/mongoose · error · MongooseError

Query.prototype.find() no longer accepts a callback

Error message

Query.prototype.find() no longer accepts a callback

What it means

Mongoose 7.0 removed callback-style execution from all query methods; Query.prototype.find() throws immediately if its first argument or the second positional argument (arguments[1]) is a function. The throw happens at query-construction time, before any database call, so legacy code like Model.find({}, cb) fails fast instead of silently never invoking the callback.

Source

Thrown at lib/query.js:2550

/**
 * Find all documents that match `selector`. The result will be an array of documents.
 *
 * If there are too many documents in the result to fit in memory, use
 * [`Query.prototype.cursor()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.cursor())
 *
 * #### Example:
 *
 *     const arr = await Movie.find({ year: { $gte: 1980, $lte: 1989 } });
 *
 * @param {object|ObjectId} [filter] mongodb filter. If not specified, returns all documents.
 * @return {Query} this
 * @api public
 */

Query.prototype.find = function(conditions) {
  if (typeof conditions === 'function' ||
      typeof arguments[1] === 'function') {
    throw new MongooseError('Query.prototype.find() no longer accepts a callback');
  }

  this.op = 'find';

  if (canMerge(conditions)) {
    this.merge(conditions);

    prepareDiscriminatorCriteria(this);
  } else if (conditions != null) {
    this.error(new ObjectParameterError(conditions, 'filter', 'find'));
  }

  return this;
};

/**
 * Merges another Query or conditions object into this one.
 *

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Use async/await: const docs = await Model.find({})
  2. Or promise chaining: Model.find({}).then(docs => ...).catch(err => ...)
  3. Grep the codebase for .find( calls with a trailing function argument and remove the callbacks; follow the Mongoose 6 to 7 migration guide

Example fix

// before (mongoose 6 and earlier)
Model.find({ active: true }, (err, docs) => {
  if (err) return next(err);
  res.json(docs);
});

// after (mongoose 7/8)
try {
  const docs = await Model.find({ active: true });
  res.json(docs);
} catch (err) {
  next(err);
}
Defensive patterns

Strategy: validation

Validate before calling

// Optional dev-time wrapper that fails fast with a clearer message
function findSafe(model, filter, options) {
  if ([filter, options].some(v => typeof v === 'function')) {
    throw new Error('find() is promise-only in Mongoose 7+; remove the callback');
  }
  return model.find(filter, options);
}

Type guard

const isLegacyCallback = (v) => typeof v === 'function';

Try / catch

try {
  const docs = await Model.find(filter);
} catch (err) {
  if (err?.message?.includes('no longer accepts a callback')) {
    // a call site still uses the removed callback signature: fix it there
  }
  throw err;
}

Prevention

When it happens

Trigger: Model.find({}, (err, docs) => {...}); Model.find(cb); passing a function in the filter slot (.find(someMapper)); wrappers built on the `async` library (async.waterfall) that forward nodeback callbacks positionally.

Common situations: Upgrading mongoose 6 to 7/8 without migrating callbacks (deprecated in 6, removed in 7); old tutorials and Stack Overflow snippets; large legacy codebases where a single un-migrated call throws on the first request after deploy.

Related errors


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