Automattic/mongoose · error · MongooseError
Model.syncIndexes() no longer accepts a callback
Error message
Model.syncIndexes() no longer accepts a callback
What it means
Model.syncIndexes() reconciles the indexes defined in the schema with those in MongoDB (creating missing ones, dropping/hiding stale ones) and returns a promise of dropped index names. Since Mongoose 7 it accepts only an options object; a function in either positional slot throws immediately.
Source
Thrown at lib/model.js:1332
* performance. Before running `syncIndexes()`, you can use the [`diffIndexes()` function](#Model.diffIndexes())
* to check what indexes `syncIndexes()` will drop and create.
*
* #### Example:
*
* const { toDrop, toCreate } = await Model.diffIndexes();
* toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop
* toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create
*
* @param {object} [options] options to pass to `ensureIndexes()`
* @param {boolean} [options.hideIndexes=false] set to `true` to hide indexes instead of dropping. Requires MongoDB server 4.4 or higher
* @return {Promise}
* @api public
*/
Model.syncIndexes = async function syncIndexes(options) {
_checkContext(this, 'syncIndexes');
if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function') {
throw new MongooseError('Model.syncIndexes() no longer accepts a callback');
}
const autoCreate = options?.autoCreate ??
this.schema.options?.autoCreate ??
this.db.config.autoCreate ??
this.db.base?.options?.autoCreate ??
true;
if (autoCreate) {
try {
await this.createCollection();
} catch (err) {
if (err != null && (err.name !== 'MongoServerError' || err.code !== 48)) {
throw err;
}
}
}
View on GitHub (pinned to 49cdab0136)
Solutions
- Await it: `const dropped = await User.syncIndexes();`
- For many models: `await Promise.all(mongoose.modelNames().map(n => mongoose.model(n).syncIndexes()))`
- Check `Model.diffIndexes()` first if you only want to preview changes without the misleading callback error
Example fix
// before
User.syncIndexes(function(err, dropped) { ... });
// after
const dropped = await User.syncIndexes(); Defensive patterns
Strategy: validation
Validate before calling
const isFn = (a) => typeof a === 'function';
if (isFn(options) || isFn(arguments[1])) throw new TypeError('syncIndexes() is promise-only');
const dropped = await User.syncIndexes(options); Prevention
- Use TypeScript so callback overloads are absent and flagged at build time
- Preview with `await Model.diffIndexes()` in CI instead of ad-hoc callback scripts
When it happens
Trigger: `User.syncIndexes({ hideIndexes: true }, cb)` or `User.syncIndexes(cb)`; deployment scripts from the callback era that call syncIndexes per model in a loop with a callback.
Common situations: Mongoose 6-to-7 upgrades; index-sync utilities iterated with async.forEach-style callback helpers from older libraries.
Related errors
- Model.init() no longer accepts a callback
- Model.cleanIndexes() 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/2772d7caf05fdb89.
Report an issue: GitHub.