Automattic/mongoose · error · MongooseError
Query.prototype.findOne() no longer accepts a callback
Error message
Query.prototype.findOne() no longer accepts a callback
What it means
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.
Source
Thrown at lib/query.js:2834
* const query = Kitten.where({ color: 'white' });
* const kitten = await query.findOne();
*
* @param {object} [filter] mongodb selector
* @param {object} [projection] optional fields to return
* @param {object} [options] see [`setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
* @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.
* @return {Query} this
* @see findOne https://www.mongodb.com/docs/manual/reference/method/db.collection.findOne/
* @see Query.select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()
* @api public
*/
Query.prototype.findOne = function(conditions, projection, options) {
if (typeof conditions === 'function' ||
typeof projection === 'function' ||
typeof options === 'function' ||
typeof arguments[3] === 'function') {
throw new MongooseError('Query.prototype.findOne() no longer accepts a callback');
}
this.op = 'findOne';
if (options) {
this.setOptions(options);
}
if (projection) {
this.select(projection);
}
if (canMerge(conditions)) {
this.merge(conditions);
prepareDiscriminatorCriteria(this);
} else if (conditions != null) {
this.error(new ObjectParameterError(conditions, 'filter', 'findOne'));View on GitHub (pinned to 49cdab0136)
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
Example fix
// before
Model.findOne({ email }, (err, user) => {
if (err) return next(err);
if (!user) return res.status(401).end();
res.json(user);
});
// after
try {
const user = await Model.findOne({ email });
if (!user) return res.status(401).end();
res.json(user);
} catch (err) {
next(err);
} Defensive patterns
Strategy: validation
Validate before calling
function findOneSafe(model, conditions, projection, options) {
if ([conditions, projection, options].some(v => typeof v === 'function')) {
throw new Error('findOne() is promise-only in Mongoose 7+');
}
return model.findOne(conditions, projection, options);
} Type guard
const isLegacyCallback = (v) => typeof v === 'function';
Try / catch
try {
const user = await Model.findOne({ email });
} catch (err) {
if (err?.message?.includes('no longer accepts a callback')) {
// leftover callback signature at this call site
}
throw err;
} Prevention
- 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
When it happens
Trigger: Model.findOne({ email }, (err, user) => {...}); Model.findOne({}, 'name', cb); a function accidentally passed as the projection, e.g. .findOne({}, buildProjection) instead of .findOne({}, buildProjection()).
Common situations: Legacy authentication middleware doing User.findOne(email, cb); upgrading to Mongoose 7/8; refactors that reordered arguments but left the callback in place.
Related errors
- Query.prototype.find() no longer accepts a callback
- Query.prototype.estimatedDocumentCount() no longer accepts a
- Query.prototype.countDocuments() no longer accepts a callbac
- Query.prototype.distinct() no longer accepts a callback
- Query.prototype.deleteOne() no longer accepts a callback
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/bd48cbef961af0d3.
Report an issue: GitHub.