Automattic/mongoose · error · Error
Invalid geoJSON type for $geoWithin "${geoWithinType}", must
Error message
Invalid geoJSON type for $geoWithin "${geoWithinType}", must be "Polygon" or "MultiPolygon" What it means
$geoWithin accepts a GeoJSON $geometry only when its type is 'Polygon' or 'MultiPolygon' -- a search boundary must be an area, not a point or line. lib/cast.js checks the type against an allow-list before using the coordinates and throws this Error for anything else (Point, LineString, GeometryCollection, ...).
Source
Thrown at lib/cast.js:273
value.$minDistance,
context
);
}
if (isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({
transform: false,
virtuals: false
});
}
value = value.$geometry.coordinates;
} else if (geo === '$geoWithin') {
if (value.$geometry) {
if (isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({ virtuals: false });
}
const geoWithinType = value.$geometry.type;
if (ALLOWED_GEOWITHIN_GEOJSON_TYPES.indexOf(geoWithinType) === -1) {
throw new Error('Invalid geoJSON type for $geoWithin "' +
geoWithinType + '", must be "Polygon" or "MultiPolygon"');
}
value = value.$geometry.coordinates;
} else {
value = value.$box || value.$polygon || value.$center ||
value.$centerSphere;
if (isMongooseObject(value)) {
value = value.toObject({ virtuals: false });
}
}
}
_cast(value, numbertype, context);
continue;
}
}
if (schema.nested[path]) {View on GitHub (pinned to 49cdab0136)
Solutions
- Put the Polygon/MultiPolygon inside $geoWithin.$geometry and keep the Point as the queried field's value
- For the inverse direction (point input, polygon field) use { loc: { $geoIntersects: { $geometry: pointGeoJSON } } }
- Validate the type against ['Polygon', 'MultiPolygon'] before building the query
Example fix
// before: a Point cannot bound a $geoWithin
Model.find({ loc: { $geoWithin: { $geometry: { type: 'Point', coordinates: [1, 1] } } } });
// after: find points inside a polygon
Model.find({ loc: { $geoWithin: { $geometry: { type: 'Polygon', coordinates: [[[0, 0], [3, 0], [3, 3], [0, 0]]] } } } }); Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = ['Polygon', 'MultiPolygon'];
function assertGeoWithinGeometry(clause) {
const geo = clause && clause.$geoWithin;
if (geo && geo.$geometry && !ALLOWED.includes(geo.$geometry.type)) {
throw new TypeError(
`$geoWithin type must be Polygon or MultiPolygon, got ${geo.$geometry.type}`
);
}
} Type guard
function isAreaGeometry(g) {
return g != null &&
(g.type === 'Polygon' || g.type === 'MultiPolygon') &&
Array.isArray(g.coordinates);
} Prevention
- Remember the direction: the field holds the point, $geoWithin holds the area
- Centralize GeoJSON construction in helpers that hard-code the type
- Validate GeoJSON payloads (type + coordinates shape) at the API boundary
When it happens
Trigger: Model.find({ loc: { $geoWithin: { $geometry: { type: 'Point', coordinates: [lng, lat] } } } }); a type field driven by a variable that holds the queried document's type instead of the boundary's; boundary data stored as LineString.
Common situations: Inverting a point-in-polygon query (Point placed in $geoWithin, Polygon used as the field value); copying a $near/$geometry example where Point is correct; unvalidated GeoJSON from clients; renaming GeoJSON types during data migrations.
Related errors
- $near must be either an array or an object with a $geometry
- Bad $within parameter: ${JSON.stringify(val)}
- Invalid $within $box argument. Expected an array, received $
- Invalid addFields() argument. Must be an object
- Query filter must be an object, got an array ${util.inspect(
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/b79792892b99c994.
Report an issue: GitHub.