Automattic/mongoose · error · MongooseError
Document deleteOne pre hooks cannot overwrite arguments
Error message
Document deleteOne pre hooks cannot overwrite arguments
What it means
Document-style deleteOne middleware (pre('deleteOne', { document: true, query: false })) runs inside Mongoose's wrapper with fixed arguments (doc, options). If the pre hook replaces those arguments — classically by calling next() with values, e.g. next(null, otherDoc, otherOptions), or via a plugin that proxies and forwards replaced args — Mongoose throws this MongooseError, because its wrapper must execute with the original document and options.
Source
Thrown at lib/model.js:848
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();
}
}
const preFilter = buildMiddlewareFilter(options, 'pre');
const postFilter = buildMiddlewareFilter(options, 'post');
query.pre(async function queryPreDeleteOne() {
const res = await self.constructor._middleware.execPre('deleteOne', self, [self, options], { filter: preFilter });
// `self` is passed to pre hooks as argument for backwards compatibility, but that
// isn't the actual arguments passed to the wrapped function.
if (res[0] !== self || res[1] !== options) {
throw new MongooseError('Document deleteOne pre hooks cannot overwrite arguments');
}
query.deleteOne(where, options);
// Apply custom where conditions _after_ document deleteOne middleware for
// consistency with save() - sharding plugin needs to set $where
if (self.$where != null) {
this.where(self.$where);
}
return res;
});
query.pre(function callSubdocPreHooks() {
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPre('deleteOne', subdoc, [subdoc], { filter: preFilter })));
});
query.pre(function skipIfAlreadyDeleted() {
if (self.$__.isDeleted) {
throw new Kareem.skipWrappedFunction();
}
});
query.post(function callSubdocPostHooks() {View on GitHub (pinned to 49cdab0136)
Solutions
- Call next() with no arguments (or write async hooks with no return value) in document deleteOne pre hooks
- Modify behavior through `this` (the document) instead of replacing arguments
- Apply custom conditions via this.$where, or use query-level hooks (pre('deleteOne', { query: true, document: false })) and shape the Query
Example fix
// before
schema.pre('deleteOne', { document: true, query: false }, function (next) {
next(null, this, { soft: true }); // replaces (doc, options) -> throws
});
// after
schema.pre('deleteOne', { document: true, query: false }, async function () {
this.deletedAt = new Date(); // mutate the document instead
}); Defensive patterns
Strategy: try-catch
Try / catch
try {
await doc.deleteOne();
} catch (err) {
if (err instanceof mongoose.MongooseError && /pre hooks cannot overwrite arguments/.test(err.message)) {
// audit registered pre('deleteOne', { document: true }) hooks and plugins:
// ensure they call next() with no arguments and mutate `this` instead
} else throw err;
} Prevention
- In document deleteOne pre hooks, always call next() with zero arguments (or use async functions without return values)
- Change document state via `this`, extra conditions via this.$where, never by replacing hook arguments
- When integrating plugins that wrap middleware, verify they pass arguments through unchanged
When it happens
Trigger: A schema hook like schema.pre('deleteOne', { document: true, query: false }, function (next) { next(null, this, {}); }) followed by doc.deleteOne(); also plugins (soft-delete, audit trails) that wrap deleteOne middleware and pass replaced arguments through.
Common situations: Writing hooks with other libraries' semantics where next() carries results; porting query-middleware patterns that reshape arguments to document middleware; plugin interop layers around deleteOne.
Related errors
- Document updateOne pre hooks cannot overwrite arguments
- For your own good, Mongoose does not know how to remove an A
- Arguments must be aggregate pipeline operators
- Invalid addFields() argument. Must be an object
- Invalid project() argument. Must be string or object
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/66dd1203846d44e3.
Report an issue: GitHub.