Automattic/mongoose · error · TypeError

Invalid $within $box argument. Expected an array, received $

Error message

Invalid $within $box argument. Expected an array, received ${arr}

What it means

When casting $within (and $geoWithin legacy shapes) with $box or $polygon, Mongoose iterates the argument and requires every entry to be an array of coordinates, which it then casts to numbers. If any entry is not an array — a flattened number, a string, an object — it throws TypeError 'Invalid $within $box argument. Expected an array, received <val>'.

Source

Thrown at lib/schema/operators/geospatial.js:66

      // ignore unknowns
      break;
  }

  _castMinMaxDistance(self, val);

  return val;
}

function cast$within(val) {
  _castMinMaxDistance(this, val);

  if (val.$box || val.$polygon) {
    const type = val.$box ? '$box' : '$polygon';
    val[type].forEach(arr => {
      if (!Array.isArray(arr)) {
        const msg = 'Invalid $within $box argument. '
            + 'Expected an array, received ' + arr;
        throw new TypeError(msg);
      }
      arr.forEach((v, i) => {
        arr[i] = castToNumber.call(this, v);
      });
    });
  } else if (val.$center || val.$centerSphere) {
    const type = val.$center ? '$center' : '$centerSphere';
    val[type].forEach((item, i) => {
      if (Array.isArray(item)) {
        item.forEach((v, j) => {
          item[j] = castToNumber.call(this, v);
        });
      } else {
        val[type][i] = castToNumber.call(this, item);
      }
    });
  } else if (val.$geometry) {
    cast$geometry(val, this);

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Pass $box as exactly two coordinate arrays: `{ $box: [[x1, y1], [x2, y2]] }` (bottom-left then top-right, [lng, lat])
  2. Pass $polygon as an array of point arrays: `{ $polygon: [[0,0],[3,6],[6,0]] }`
  3. Convert client map bounds to arrays before querying: `[[w,s],[e,n]]`
  4. Prefer modern $geoWithin with $geometry (`{ loc: { $geoWithin: { $geometry: { type: 'Polygon', coordinates: [...] } } } }`) — $within is a deprecated legacy operator

Example fix

// before
Model.find({ loc: { $within: { $box: [0, 0, 10, 10] } } });

// after
Model.find({ loc: { $within: { $box: [[0, 0], [10, 10]] } } });
Defensive patterns

Strategy: validation

Validate before calling

function toBoxFilter(w, s, e, n) {
  if (![w, s, e, n].every(Number.isFinite)) throw new Error('bounds must be numbers');
  return { $within: { $box: [[w, s], [e, n]] } }; // two points, not flattened
}

Type guard

function isBoxArg(v) {
  return Array.isArray(v) && v.length === 2 && v.every(p => Array.isArray(p) && p.every(Number.isFinite));
}

Try / catch

try { await Model.find({ loc: { $within: { $box: box } } }); } catch (err) { if (/Invalid \$within \$box argument/.test(err.message)) { return badRequest('$box needs [[x1,y1],[x2,y2]]'); } throw err; }

Prevention

When it happens

Trigger: `{ loc: { $within: { $box: [0, 0, 10, 10] } } }` — coordinates flattened into four numbers instead of two points; `{ $polygon: '34,28,35,29' }` (string); `{ $box: [{ x: 0, y: 0 }, { x: 10, y: 10 }] }` (point objects instead of coordinate arrays).

Common situations: Flattening corner coordinates when building map-viewport queries; sending bounding boxes from client map libraries (Leaflet/Google return LatLng objects) without conversion; mixing up $box's two-point contract with $polygon's n-point polygon.

Related errors


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