Automattic/mongoose · error · TypeError
Invalid sort value: { ${key}: ${val} }
Error message
Invalid sort value: { ${key}: ${val} } What it means
_handleSortValue(), used by sort()'s object, array, and Map branches, accepts exactly 1, -1, 'asc', 'ascending', 'desc', 'descending', or a { $meta: ... } object; anything else throws a TypeError echoing the offending key/value. Comparisons are exact, so 'ASC' (uppercase), 'desc ' (trailing space), 0, 2, and 'up' all fail.
Source
Thrown at lib/query.js:3209
return this;
};
/*!
* Convert sort values
*/
function _handleSortValue(val, key) {
if (val === 1 || val === 'asc' || val === 'ascending') {
return 1;
}
if (val === -1 || val === 'desc' || val === 'descending') {
return -1;
}
if (val?.$meta != null) {
return { $meta: val.$meta };
}
throw new TypeError('Invalid sort value: { ' + key + ': ' + val + ' }');
}
/**
* Declare and/or execute this query as a `deleteOne()` operation. Works like
* remove, except it deletes at most one document regardless of the `single`
* option.
*
* This function triggers `deleteOne` middleware.
*
* #### Example:
*
* await Character.deleteOne({ name: 'Eddard Stark' });
*
* This function calls the MongoDB driver's [`Collection#deleteOne()` function](https://mongodb.github.io/node-mongodb-native/7.0/classes/Collection.html#deleteOne).
* The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
* object that contains 2 properties:
*
* - `acknowledged`: booleanView on GitHub (pinned to 49cdab0136)
Solutions
- Normalize input before use: trim + lowercase, then map 'asc'/'ascending'/'1' to 1 and 'desc'/'descending'/'-1' to -1
- Whitelist field names and directions at the route boundary and reject invalid values with a 400
- Default an invalid direction to a safe value (e.g. 1) instead of forwarding it
Example fix
// before
const q = Model.find().sort({ name: req.query.order }); // req.query.order = 'ASC'
// after
const raw = String(req.query.order ?? '').trim().toLowerCase();
const dir = ['desc', 'descending', '-1'].includes(raw) ? -1 : 1;
const q = Model.find().sort({ name: dir }); Defensive patterns
Strategy: validation
Validate before calling
const DIRECTIONS = new Set(['asc', 'ascending', '1', 'desc', 'descending', '-1']);
function toDirection(raw) {
const d = String(raw ?? '').trim().toLowerCase();
if (!DIRECTIONS.has(d)) return 1;
return d.startsWith('a') || d === '1' ? 1 : -1;
}
const q = Model.find().sort({ name: toDirection(req.query.order) }); Type guard
const isValidDirection = (v) => [1, -1, 'asc', 'ascending', 'desc', 'descending'].includes(v) || v?.$meta != null;
Prevention
- Trim and lowercase user-supplied directions before use
- Whitelist sort fields and directions at the API boundary
- Remember 'ASC'/'DESC' uppercase values are rejected — exact match only
When it happens
Trigger: .sort({ name: 'ASC' }) with uppercase from SQL habits; .sort({ age: 2 }) or .sort({ age: 0 }); .sort({ name: 'up' }); passing req.query.order straight into the sort object; .sort({ score: { $meta: undefined } }).
Common situations: User-supplied sort directions (req.query.order='ASC') forwarded unnormalized; uppercase 'ASC'/'DESC' from SQL-style APIs; truthy numbers mistaken for directions.
Related errors
- Invalid sort() argument, must be array of arrays
- Invalid sort() argument. Must be a string, object, array, or
- Invalid addFields() argument. Must be an object
- Invalid select() argument. Must be string or object.
- sort() takes at most 2 arguments
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/1b09dee64007b5f6.
Report an issue: GitHub.