Automattic/mongoose · warning · TypeError
Invalid sort() argument. Must be a string or object.
Error message
Invalid sort() argument. Must be a string or object.
What it means
While building indexes for a model (Model.init() / ensureIndexes during compile or model.syncIndexes()), Mongoose inspects each index spec; MongoDB always creates a unique index on _id and does not allow a second, different index on the same key. isDefaultIdIndex() detects specs that try to redefine the _id index (e.g. { _id: 1 } or {_id: 1} with extra options), and Mongoose warns that the custom definition will not be applied as expected.
Source
Thrown at lib/aggregate.js:677
if (arg[field] instanceof Object && arg[field].$meta) {
sort[field] = arg[field];
return;
}
sort[field] = desc.indexOf(arg[field]) === -1 ? 1 : -1;
});
} else if (arguments.length === 1 && typeof arg === 'string') {
arg.split(/\s+/).forEach(function(field) {
if (!field) {
return;
}
const ascend = field[0] === '-' ? -1 : 1;
if (ascend === -1) {
field = field.substring(1);
}
sort[field] = ascend;
});
} else {
throw new TypeError('Invalid sort() argument. Must be a string or object.');
}
return this.append({ $sort: sort });
};
/**
* Appends new $unionWith operator to this aggregate pipeline.
*
* #### Example:
*
* aggregate.unionWith({ coll: 'users', pipeline: [ { $match: { _id: 1 } } ] });
*
* @see $unionWith https://www.mongodb.com/docs/manual/reference/operator/aggregation/unionWith
* @param {object} options to $unionWith query as described in the above link
* @return {Aggregate}
* @api public
*/
View on GitHub (pinned to 49cdab0136)
Solutions
- Remove the _id entry from schema.index() calls — MongoDB guarantees the _id unique index automatically.
- Remove index: true from the _id field definition: { _id: Schema.Types.ObjectId } is enough.
- If you need a custom _id type (e.g. Number), that is supported — just do not also declare an index on it.
- Run model.syncIndexes() after cleaning up and confirm via db.collection.getIndexes() that only one _id index exists.
Example fix
// before
const schema = new Schema({ _id: { type: ObjectId, index: true } });
schema.index({ _id: 1 }, { name: 'custom_id' });
// after
const schema = new Schema({ _id: ObjectId }); // default unique index is automatic Defensive patterns
Strategy: validation
Validate before calling
function sanitizeIndexes(schema) {
const json = schema.indexes(); // [[fields, options], ...]
for (const [fields] of json) {
const keys = Object.keys(fields);
if (keys.length === 1 && keys[0] === '_id') {
throw new Error('Remove custom index on _id; MongoDB creates it automatically');
}
}
} Prevention
- Never declare indexes on _id in schemas or schema.index().
- Do not blindly convert db.collection.getIndexes() output into schema.index() calls — skip _id.
- Review generated/seed schemas for index: true on _id fields.
When it happens
Trigger: schema.index({ _id: 1 }) or schema.index({ _id: 1 }, { unique: true, name: 'custom' }); defining { _id: { type: Schema.Types.ObjectId, index: true } } in the schema; setting sparse/expireAfterSeconds options on an _id index spec.
Common situations: Auto-generated index definitions from tooling that indexes every field; teams copying an index list from mongo shell explain output back into the schema; migration scripts that materialize existing DB indexes as schema.index() calls including the implicit _id one.
Related errors
- If thenExpr or elseExpr is string, it must be either $$DESCE
- Aggregate `near()` must be called with non-nullish argument
- Cannot create use schema for property "${path}" because the
- Invalid arg "${arg}" to unwind(), must be string or object
- Invalid arg "${arg}" to sortByCount(), must be string or obj
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/459fe6460b4b047a.
Report an issue: GitHub.