Automattic/mongoose · error · MongooseError

Invalid field "" passed to sort()

Error message

Invalid field "" passed to sort()

What it means

Before executing, Mongoose inspects query.options.sort and rejects an object that owns an empty-string key (sort({ '': 1 })). Sorting on an empty field name is meaningless and usually the result of building a sort object dynamically, so the check catches it client-side with a clear message.

Source

Thrown at lib/query.js:4767

  this._validateOp();
  if (typeof op === 'string') {
    this.op = op;
  }

  if (this.op == null) {
    throw new MongooseError('Query must have `op` before executing');
  }
  if (this.model == null) {
    throw new MongooseError('Query must have an associated model before executing');
  }

  const thunk = opToThunk.get(this.op);
  if (!thunk) {
    throw new MongooseError('Query has invalid `op`: "' + this.op + '"');
  }

  if (this.options?.sort && typeof this.options.sort === 'object' && Object.hasOwn(this.options.sort, '')) {
    throw new MongooseError('Invalid field "" passed to sort()');
  }

  if (this._execCount > 0) {
    let str = this.toString();
    if (str.length > 60) {
      str = str.slice(0, 60) + '...';
    }
    throw new MongooseError('Query was already executed: ' + str);
  }
  this._execCount++;

  const _this = this;
  return traceQuery(async function maybeTracedQueryExec() {
    let skipWrappedFunction = null;
    try {
      await _this._hooks.execPre('exec', _this, []);
    } catch (err) {
      if (err instanceof Kareem.skipWrappedFunction) {

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Validate/normalize user-supplied sort fields and skip empties: `if (field) sort[field] = dir;`.
  2. Default to a real field or no sort at all when the input is empty.
  3. Add allowlist checks so only known schema fields reach sort().

Example fix

// before
const sort = { [req.query.sortBy]: 1 }; // req.query.sortBy === '' → Invalid field "" passed to sort()
await Model.find().sort(sort).exec();

// after
const allowed = ['name', 'createdAt', 'price'];
const sortBy = allowed.includes(req.query.sortBy) ? req.query.sortBy : 'createdAt';
await Model.find().sort({ [sortBy]: 1 }).exec();
Defensive patterns

Strategy: validation

Validate before calling

function buildSort(sortBy, dir = 1, allowed = ['name','createdAt','price']) {
  if (!sortBy || !allowed.includes(sortBy)) return {};
  return { [sortBy]: dir };
}

Type guard

const hasEmptySortKey = (sort) => sort != null && typeof sort === 'object' && Object.hasOwn(sort, '');

Try / catch

try { await Model.find().sort(sort).exec(); } catch (err) { if (err instanceof mongoose.Error && /Invalid field ""/.test(err.message)) { delete sort['']; return Model.find().sort(sort).exec(); } throw err; }

Prevention

When it happens

Trigger: `query.sort({ '': 1 })`; `query.sort('')` or `query.sort('name ')` trimmed to an empty field; sort objects built as `{ [req.query.sortField]: 1 }` when sortField is '' or undefined-coerced; CSV/env-driven sort fields that arrive empty.

Common situations: Exposing a sort parameter from an HTTP query string or config without validating it; defaulting sort keys to '' instead of skipping; string parsing that splits on a delimiter and yields empty tokens.

Related errors


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