Automattic/mongoose · error · MongooseError
Model.prototype.deleteOne() no longer accepts a callback
Error message
Model.prototype.deleteOne() no longer accepts a callback
What it means
Like save(), Model.prototype.deleteOne() lost its callback form in Mongoose 7: it takes only an options object and returns a Query (thenable). Passing a function as the first or second argument throws this MongooseError immediately, guarding against a silently-never-invoked callback.
Source
Thrown at lib/model.js:819
*
* await product.deleteOne();
* await Product.findById(product._id); // null
*
* Since `deleteOne()` returns a Query, the `deleteOne()` will **not** execute unless you use either `await`, `.then()`, `.catch()`, or [`.exec()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.exec())
*
* #### Example:
*
* product.deleteOne(); // Doesn't do anything
* product.deleteOne().exec(); // Deletes the document, returns a promise
*
* @return {Query} Query
* @api public
*/
Model.prototype.deleteOne = function deleteOne(options) {
if (typeof options === 'function' ||
typeof arguments[1] === 'function') {
throw new MongooseError('Model.prototype.deleteOne() no longer accepts a callback');
}
if (!options) {
options = {};
}
if (Object.hasOwn(options, 'session')) {
this.$session(options.session);
}
const self = this;
const where = this.$__where();
const query = self.constructor.deleteOne();
if (this.$session() != null) {
if (!('session' in query.options)) {
query.options.session = this.$session();
}View on GitHub (pinned to 49cdab0136)
Solutions
- Use await doc.deleteOne() (optionally with .exec())
- Promisify at the API boundary if external consumers still expect callbacks: doc.deleteOne(opts).then(r => cb(null, r), cb)
- Grep for `.deleteOne(function` and `.deleteOne(.*, *cb` during the migration
Example fix
// before
product.deleteOne(function (err) {
if (err) return next(err);
res.end();
});
// after
await product.deleteOne();
res.end(); Defensive patterns
Strategy: validation
Validate before calling
// Guard a shared helper against callback-style deleteOne
async function removeDoc(doc, options) {
if (typeof options === 'function' || typeof arguments[2] === 'function') {
throw new Error('deleteOne() is promise-based — await it instead');
}
return doc.deleteOne(options);
} Type guard
const isCallback = (x) => typeof x === 'function';
Try / catch
try {
await doc.deleteOne({ session });
} catch (err) {
// handle normally; no callback path exists
} Prevention
- Use await doc.deleteOne() everywhere after upgrading to Mongoose 7
- Search the repo for deleteOne(function / deleteOne(.*cb patterns during migration
- Update shared CRUD helpers to return promises and let callers await them
When it happens
Trigger: doc.deleteOne(function (err) { ... }) or doc.deleteOne({ session }, cb) after upgrading to Mongoose 7+.
Common situations: Mongoose 6-to-7 migrations; shared CRUD helpers with callback signatures; older Stack Overflow snippets pasted into modern code.
Related errors
- Model.prototype.save() no longer accepts a callback
- Model.exists() no longer accepts a callback
- Model.findOneAndDelete() no longer accepts a callback
- Model.findByIdAndDelete() 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/4ce9868234e625e3.
Report an issue: GitHub.