Automattic/mongoose · warning · MongooseError

Aggregate `near()` argument must have a `near` property

Error message

Aggregate `near()` argument must have a `near` property

What it means

validateSync() runs schema validators synchronously and returns a ValidationError (or undefined), but it skips middleware (pre/post validate hooks) and async validators. Mongoose has deprecated it: the warning prints on every call, and the method will be removed in Mongoose 10 in favor of the async Document.prototype.validate().

Source

Thrown at lib/aggregate.js:413

 *       spherical: true,
 *     });
 *
 * @see $geoNear https://www.mongodb.com/docs/manual/reference/aggregation/geoNear/
 * @method near
 * @memberOf Aggregate
 * @instance
 * @param {object} arg
 * @param {object|number[]} arg.near GeoJSON point or coordinates array
 * @return {Aggregate}
 * @api public
 */

Aggregate.prototype.near = function(arg) {
  if (arg == null) {
    throw new MongooseError('Aggregate `near()` must be called with non-nullish argument');
  }
  if (arg.near == null) {
    throw new MongooseError('Aggregate `near()` argument must have a `near` property');
  }
  const coordinates = Array.isArray(arg.near) ? arg.near : arg.near.coordinates;
  if (typeof arg.near === 'object' && (!Array.isArray(coordinates) || coordinates.length < 2 || coordinates.find(c => typeof c !== 'number'))) {
    throw new MongooseError(`Aggregate \`near()\` argument has invalid coordinates, got "${coordinates}"`);
  }

  const op = {};
  op.$geoNear = arg;
  return this.append(op);
};

/*!
 * define methods
 */

'group match skip limit out densify fill'.split(' ').forEach(function($operator) {
  Aggregate.prototype[$operator] = function(arg) {
    const op = {};

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Replace with await doc.validate() and catch the rejected ValidationError: try { await doc.validate(); } catch (err) { /* err instanceof mongoose.Error.ValidationError */ }.
  2. Port assertions in tests to async: await expect(doc.validate()).rejects.toThrow(mongoose.Error.ValidationError).
  3. Note that validate() also runs middleware and async validators — review any behavior that silently differed under validateSync().
  4. Do not wait for Mongoose 10: the method is removed there, so the migration is mandatory before upgrading.

Example fix

// before
const err = doc.validateSync();
if (err) console.log(err.message);

// after
try {
  await doc.validate();
} catch (err) {
  if (err instanceof mongoose.Error.ValidationError) console.log(err.message);
}
Defensive patterns

Strategy: validation

Validate before calling

// static check: grep for validateSync in CI
// require('child_process').execSync("grep -rn 'validateSync(' src/ && exit 1 || exit 0")

Try / catch

// async replacement pattern that preserves the old control flow:
try {
  await doc.validate();
} catch (err) {
  if (err instanceof mongoose.Error.ValidationError) {
    // handle like the old validateSync() return value
  } else throw err;
}

Prevention

When it happens

Trigger: Calling doc.validateSync() or doc.validateSync(['email']) anywhere in application or test code; passing the options object form doc.validateSync({ pathsToSkip: ['name'] }) — each call prints the deprecation warning once (utils.warn).

Common situations: Long-lived codebases that predate async validate; tests that synchronously assert validation errors; upgrading Mongoose 7/8/9 where the warning appears in CI logs and fails strict log-scanning tests; code that relied on the returned ValidationError without handling promises.

Related errors


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