Automattic/mongoose · error · TypeError

Invalid sort() argument, must be array of arrays

Error message

Invalid sort() argument, must be array of arrays

What it means

When sort() receives an array, every element must itself be a [key, direction] pair. A flat array such as .sort(['name', -1]) — a single pair wrapped once instead of twice — or a mixed array like [['a', 1], 'b'] fails this TypeError inside the array branch of sort().

Source

Thrown at lib/query.js:3165

    this.options.sort = {};
  }
  const sort = this.options.sort;
  if (typeof arg === 'string') {
    const properties = arg.indexOf(' ') === -1 ? [arg] : arg.split(' ');
    for (let property of properties) {
      const ascend = '-' == property[0] ? -1 : 1;
      if (ascend === -1) {
        property = property.slice(1);
      }
      if (specialProperties.has(property)) {
        continue;
      }
      sort[property] = ascend;
    }
  } else if (Array.isArray(arg)) {
    for (const pair of arg) {
      if (!Array.isArray(pair)) {
        throw new TypeError('Invalid sort() argument, must be array of arrays');
      }
      const key = '' + pair[0];
      if (specialProperties.has(key)) {
        continue;
      }
      sort[key] = _handleSortValue(pair[1], key);
    }
  } else if (typeof arg === 'object' && arg != null && !(arg instanceof Map)) {
    for (const key of Object.keys(arg)) {
      if (specialProperties.has(key)) {
        continue;
      }
      sort[key] = _handleSortValue(arg[key], key);
    }
  } else if (arg instanceof Map) {
    for (let key of arg.keys()) {
      key = '' + key;
      if (specialProperties.has(key)) {

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Wrap each pair: .sort([['name', -1]])
  2. Or use the object form: .sort({ name: -1 })
  3. When building dynamically, always push arrays: pairs.push([field, dir])

Example fix

// before
Model.find().sort(['createdAt', -1]);

// after
Model.find().sort([['createdAt', -1]]);
// or
Model.find().sort({ createdAt: -1 });
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure a dynamically built sort array only contains [key, dir] pairs
function toSortPairs(entries) {
  return entries
    .filter(e => Array.isArray(e) && typeof e[0] === 'string')
    .map(([field, dir]) => [field, dir === -1 || String(dir).startsWith('d') ? -1 : 1]);
}
const q = Model.find().sort(toSortPairs(sortInput));

Type guard

const isSortPairArray = (v) => Array.isArray(v) && v.every(p => Array.isArray(p));

Prevention

When it happens

Trigger: .sort(['name', -1]) (most common: wrapping the pair in one array); .sort([['a', 1], 'b']); dynamically building pairs and pushing bare strings among arrays.

Common situations: Converting Sequelize's order: [['field', 'DESC']] or TypeORM orderBy arrays but wrapping incorrectly; spreading a single field/direction pair into the array; untested dynamic sort builders.

Related errors


AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21). Data as JSON: /api/errors/6be7ea497ff35149. Report an issue: GitHub.