Automattic/mongoose · error · MongooseError

Query.prototype.estimatedDocumentCount() no longer accepts a

Error message

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

What it means

Query.prototype.estimatedDocumentCount(options) throws when its options parameter or the second positional argument is a function. The method takes no other parameters (it counts via collection metadata, no filter), so a function argument is almost always a leftover callback from the Mongoose 6-and-earlier era.

Source

Thrown at lib/query.js:2958

 *
 * This function triggers the following middleware.
 *
 * - `estimatedDocumentCount()`
 *
 * #### Example:
 *
 *     await Model.find().estimatedDocumentCount();
 *
 * @param {object} [options] passed transparently to the [MongoDB driver](https://mongodb.github.io/node-mongodb-native/7.0/interfaces/EstimatedDocumentCountOptions.html)
 * @return {Query} this
 * @see estimatedDocumentCount https://mongodb.github.io/node-mongodb-native/7.0/classes/Collection.html#estimatedDocumentCount
 * @api public
 */

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

  this.op = 'estimatedDocumentCount';

  if (options != null) {
    this.setOptions(options);
  }

  return this;
};

/**
 * Specifies this query as a `countDocuments()` query. Behaves like `count()`,
 * except it always does a full collection scan when passed an empty filter `{}`.
 *
 * There are also minor differences in how `countDocuments()` handles
 * [`$where` and a couple geospatial operators](https://mongodb.github.io/node-mongodb-native/7.0/classes/Collection.html#countDocuments).
 * versus `count()`.

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Use await: const n = await Model.estimatedDocumentCount()
  2. Pass a driver options object or nothing — never a function
  3. Use .countDocuments(filter) instead when you need a filtered count

Example fix

// before
Model.estimatedDocumentCount((err, count) => {
  res.json({ total: count });
});

// after
const count = await Model.estimatedDocumentCount();
res.json({ total: count });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof options === 'function') {
  throw new TypeError('estimatedDocumentCount takes an options object, not a callback');
}
const count = await Model.estimatedDocumentCount(options);

Type guard

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

Try / catch

try {
  const n = await Model.estimatedDocumentCount();
} catch (err) {
  if (err?.message?.includes('no longer accepts a callback')) {
    // remove the callback from the estimatedDocumentCount call site
  }
  throw err;
}

Prevention

When it happens

Trigger: Model.estimatedDocumentCount(cb); query.estimatedDocumentCount({}, cb); a promise-returning helper or mapper passed in the options slot.

Common situations: Pre-Mongoose-7 stats/dashboard code using callbacks; converting removed Model.count(cb) calls to estimatedDocumentCount while keeping the callback signature.

Related errors


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