Automattic/mongoose · error · MongooseError
Model.cleanIndexes() no longer accepts a callback
Error message
Model.cleanIndexes() no longer accepts a callback
What it means
Model.cleanIndexes() drops (or hides, with `hideIndexes: true`) indexes that exist in MongoDB but not in the schema, returning the affected index names. Mongoose 7 removed its callback form, so a function in either argument slot throws before diffing starts.
Source
Thrown at lib/model.js:1573
return toDrop;
}
/**
* Deletes all indexes that aren't defined in this model's schema. Used by
* `syncIndexes()`.
*
* The returned promise resolves to a list of the dropped indexes' names as an array
*
* @param {object} [options]
* @param {string[]} [options.toDrop] if specified, contains a list of index names to drop
* @param {boolean} [options.hideIndexes=false] set to `true` to hide indexes instead of dropping. Requires MongoDB server 4.4 or higher
* @return {Promise<string[]>} list of dropped or hidden index names
* @api public
*/
Model.cleanIndexes = async function cleanIndexes(options) {
_checkContext(this, 'cleanIndexes');
if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function') {
throw new MongooseError('Model.cleanIndexes() no longer accepts a callback');
}
const model = this;
if (Array.isArray(options?.toDrop)) {
const res = await _dropIndexes(options.toDrop, model, options);
return res;
}
const res = await model.diffIndexes();
return await _dropIndexes(res.toDrop, model, options);
};
async function _dropIndexes(toDrop, model, options) {
if (toDrop.length === 0) {
return [];
}
const collection = model.$__collection;View on GitHub (pinned to 49cdab0136)
Solutions
- Await it: `const dropped = await User.cleanIndexes();`
- Pass a precomputed list if you orchestrate externally: `await User.cleanIndexes({ toDrop: ['name_1'] })`
- Batch over models with Promise.all instead of callback counters
Example fix
// before
User.cleanIndexes(function(err, dropped) { ... });
// after
const dropped = await User.cleanIndexes(); Defensive patterns
Strategy: validation
Validate before calling
const isFn = (a) => typeof a === 'function';
if (isFn(options)) throw new TypeError('cleanIndexes() is promise-only');
const dropped = await User.cleanIndexes(options); Prevention
- Prefer syncIndexes({ hideIndexes: true }) over manual cleanIndexes scripts written in callback days
- Run index maintenance through the same promise-based job runner as the rest of ops code
When it happens
Trigger: `User.cleanIndexes(cb)`; `User.cleanIndexes({ hideIndexes: true }, cb)`; teardown/maintenance scripts written against Mongoose 5/6.
Common situations: Apps upgrading mongoose majors while keeping old maintenance scripts; scripts that clean indexes for several models with a shared callback.
Related errors
- Model.init() no longer accepts a callback
- Model.syncIndexes() no longer accepts a callback
- Model.listIndexes() no longer accepts a callback
- Model.ensureIndexes() no longer accepts a callback
- Model.createIndexes() no longer accepts a callback
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/6ff74878fe2eef47.
Report an issue: GitHub.