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().

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.

Appendix: 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)