{"record":{"id":"bd48cbef961af0d3","repo":"Automattic/mongoose","slug":"query-prototype-findone-no-longer-accepts-a-call","errorCode":null,"errorMessage":"Query.prototype.findOne() no longer accepts a callback","messagePattern":"Query\\.prototype\\.findOne\\(\\) no longer accepts a callback","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/query.js","lineNumber":2834,"sourceCode":" *     const query = Kitten.where({ color: 'white' });\n *     const kitten = await query.findOne();\n *\n * @param {object} [filter] mongodb selector\n * @param {object} [projection] optional fields to return\n * @param {object} [options] see [`setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())\n * @param {boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.\n * @return {Query} this\n * @see findOne https://www.mongodb.com/docs/manual/reference/method/db.collection.findOne/\n * @see Query.select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()\n * @api public\n */\n\nQuery.prototype.findOne = function(conditions, projection, options) {\n  if (typeof conditions === 'function' ||\n      typeof projection === 'function' ||\n      typeof options === 'function' ||\n      typeof arguments[3] === 'function') {\n    throw new MongooseError('Query.prototype.findOne() no longer accepts a callback');\n  }\n\n  this.op = 'findOne';\n\n  if (options) {\n    this.setOptions(options);\n  }\n\n  if (projection) {\n    this.select(projection);\n  }\n\n  if (canMerge(conditions)) {\n    this.merge(conditions);\n\n    prepareDiscriminatorCriteria(this);\n  } else if (conditions != null) {\n    this.error(new ObjectParameterError(conditions, 'filter', 'findOne'));","sourceCodeStart":2816,"sourceCodeEnd":2852,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/query.js#L2816-L2852","documentation":"Query.prototype.findOne() checks every declared parameter (conditions, projection, options) plus arguments[3] for functions and throws this MongooseError at construction time. Like all query helpers, findOne() has been promise-only since Mongoose 7, so any nodeback-style invocation such as Model.findOne(filter, cb) is rejected before a query runs.","triggerScenarios":"Model.findOne({ email }, (err, user) => {...}); Model.findOne({}, 'name', cb); a function accidentally passed as the projection, e.g. .findOne({}, buildProjection) instead of .findOne({}, buildProjection()).","commonSituations":"Legacy authentication middleware doing User.findOne(email, cb); upgrading to Mongoose 7/8; refactors that reordered arguments but left the callback in place.","solutions":["Use async/await: const user = await Model.findOne({ email }) inside try/catch","Or Model.findOne({ email }).then(user => ...).catch(err => ...)","Sweep for findOne( calls containing 'err =>' and strip the callbacks"],"exampleFix":"// before\nModel.findOne({ email }, (err, user) => {\n  if (err) return next(err);\n  if (!user) return res.status(401).end();\n  res.json(user);\n});\n\n// after\ntry {\n  const user = await Model.findOne({ email });\n  if (!user) return res.status(401).end();\n  res.json(user);\n} catch (err) {\n  next(err);\n}","handlingStrategy":"validation","validationCode":"function findOneSafe(model, conditions, projection, options) {\n  if ([conditions, projection, options].some(v => typeof v === 'function')) {\n    throw new Error('findOne() is promise-only in Mongoose 7+');\n  }\n  return model.findOne(conditions, projection, options);\n}","typeGuard":"const isLegacyCallback = (v) => typeof v === 'function';","tryCatchPattern":"try {\n  const user = await Model.findOne({ email });\n} catch (err) {\n  if (err?.message?.includes('no longer accepts a callback')) {\n    // leftover callback signature at this call site\n  }\n  throw err;\n}","preventionTips":["Grep for findOne( calls containing 'err =>' during mongoose upgrades","Type findOne parameters explicitly so a function cannot slip into a data slot","Use async/await in auth middleware instead of nodeback style"],"tags":["mongoose","callback","promise","migration","breaking-change","findone"],"backgroundTag":"legacy-callback-removed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}