{"record":{"id":"4ce9868234e625e3","repo":"Automattic/mongoose","slug":"model-prototype-deleteone-no-longer-accepts-a-ca","errorCode":null,"errorMessage":"Model.prototype.deleteOne() no longer accepts a callback","messagePattern":"Model\\.prototype\\.deleteOne\\(\\) no longer accepts a callback","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/model.js","lineNumber":819,"sourceCode":" *\n *     await product.deleteOne();\n *     await Product.findById(product._id); // null\n *\n * 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())\n *\n * #### Example:\n *\n *     product.deleteOne(); // Doesn't do anything\n *     product.deleteOne().exec(); // Deletes the document, returns a promise\n *\n * @return {Query} Query\n * @api public\n */\n\nModel.prototype.deleteOne = function deleteOne(options) {\n  if (typeof options === 'function' ||\n      typeof arguments[1] === 'function') {\n    throw new MongooseError('Model.prototype.deleteOne() no longer accepts a callback');\n  }\n\n  if (!options) {\n    options = {};\n  }\n\n  if (Object.hasOwn(options, 'session')) {\n    this.$session(options.session);\n  }\n\n  const self = this;\n  const where = this.$__where();\n  const query = self.constructor.deleteOne();\n\n  if (this.$session() != null) {\n    if (!('session' in query.options)) {\n      query.options.session = this.$session();\n    }","sourceCodeStart":801,"sourceCodeEnd":837,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/model.js#L801-L837","documentation":"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.","triggerScenarios":"doc.deleteOne(function (err) { ... }) or doc.deleteOne({ session }, cb) after upgrading to Mongoose 7+.","commonSituations":"Mongoose 6-to-7 migrations; shared CRUD helpers with callback signatures; older Stack Overflow snippets pasted into modern code.","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"],"exampleFix":"// before\nproduct.deleteOne(function (err) {\n  if (err) return next(err);\n  res.end();\n});\n\n// after\nawait product.deleteOne();\nres.end();","handlingStrategy":"validation","validationCode":"// Guard a shared helper against callback-style deleteOne\nasync function removeDoc(doc, options) {\n  if (typeof options === 'function' || typeof arguments[2] === 'function') {\n    throw new Error('deleteOne() is promise-based — await it instead');\n  }\n  return doc.deleteOne(options);\n}","typeGuard":"const isCallback = (x) => typeof x === 'function';","tryCatchPattern":"try {\n  await doc.deleteOne({ session });\n} catch (err) {\n  // handle normally; no callback path exists\n}","preventionTips":["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"],"tags":["mongoose","delete","callback","promises","migration"],"backgroundTag":"callback-api-removed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}