{"record":{"id":"0f71373be6349ca0","repo":"Automattic/mongoose","slug":"query-prototype-countdocuments-no-longer-accepts","errorCode":null,"errorMessage":"Query.prototype.countDocuments() no longer accepts a callback","messagePattern":"Query\\.prototype\\.countDocuments\\(\\) no longer accepts a callback","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/query.js","lineNumber":3012,"sourceCode":" * Below are the operators that `count()` supports but `countDocuments()` does not,\n * and the suggested replacement:\n *\n * - `$where`: [`$expr`](https://www.mongodb.com/docs/manual/reference/operator/query/expr/)\n * - `$near`: [`$geoWithin`](https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/) with [`$center`](https://www.mongodb.com/docs/manual/reference/operator/query/center/#op._S_center)\n * - `$nearSphere`: [`$geoWithin`](https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/) with [`$centerSphere`](https://www.mongodb.com/docs/manual/reference/operator/query/centerSphere/#op._S_centerSphere)\n *\n * @param {object} [filter] mongodb selector\n * @param {object} [options]\n * @return {Query} this\n * @see countDocuments https://mongodb.github.io/node-mongodb-native/7.0/classes/Collection.html#countDocuments\n * @api public\n */\n\nQuery.prototype.countDocuments = function(conditions, options) {\n  if (typeof conditions === 'function' ||\n      typeof options === 'function' ||\n      typeof arguments[2] === 'function') {\n    throw new MongooseError('Query.prototype.countDocuments() no longer accepts a callback');\n  }\n\n  this.op = 'countDocuments';\n\n  if (canMerge(conditions)) {\n    this.merge(conditions);\n  }\n\n  if (options != null) {\n    this.setOptions(options);\n  }\n\n  return this;\n};\n\n/**\n * Execute a `distinct()` query\n *","sourceCodeStart":2994,"sourceCodeEnd":3030,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/query.js#L2994-L3030","documentation":"Query.prototype.countDocuments(conditions, options) throws if conditions, options, or a third positional argument is a function. Since Mongoose 7 the method is promise-only, so the classic tutorial pattern Model.countDocuments({}, cb) fails at query-construction time, before any database call.","triggerScenarios":"Model.countDocuments({}, (err, n) => {...}); .countDocuments(cb) with the callback in the filter slot; a function passed in the options slot.","commonSituations":"Legacy pagination totals and existence checks written against Mongoose 6; mongoose major-version upgrades; partial migrations where one count call was missed.","solutions":["Use await: const n = await Model.countDocuments({ status: 'active' })","For existence checks, prefer Model.exists(filter) or .findOne(filter).lean()","During the 6-to-7 upgrade, grep for countDocuments( with a trailing function and remove all callbacks"],"exampleFix":"// before\nModel.countDocuments({ active: true }, (err, count) => {\n  if (err) return next(err);\n  res.json({ count });\n});\n\n// after\ntry {\n  const count = await Model.countDocuments({ active: true });\n  res.json({ count });\n} catch (err) {\n  next(err);\n}","handlingStrategy":"validation","validationCode":"function countDocumentsSafe(model, conditions, options) {\n  if ([conditions, options].some(v => typeof v === 'function')) {\n    throw new Error('countDocuments() is promise-only in Mongoose 7+');\n  }\n  return model.countDocuments(conditions, options);\n}","typeGuard":"const isLegacyCallback = (v) => typeof v === 'function';","tryCatchPattern":"try {\n  const n = await Model.countDocuments({ status: 'active' });\n} catch (err) {\n  if (err?.message?.includes('no longer accepts a callback')) {\n    // fix the countDocuments call site that still passes a callback\n  }\n  throw err;\n}","preventionTips":["Replace countDocuments(filter, cb) totals with awaited calls","Prefer Model.exists(filter) for existence checks","Add a repo-wide search for ', cb)' or 'err =>' during major upgrades"],"tags":["mongoose","callback","promise","migration","breaking-change","count"],"backgroundTag":"legacy-callback-removed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}