{"record":{"id":"da9579d93b9e6097","repo":"Automattic/mongoose","slug":"near-must-be-either-an-array-or-an-object-with-a","errorCode":null,"errorMessage":"$near must be either an array or an object with a $geometry property","messagePattern":"\\$near must be either an array or an object with a \\$geometry property","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/schema/operators/geospatial.js","lineNumber":33,"sourceCode":"exports.cast$near = cast$near;\nexports.cast$within = cast$within;\n\nfunction cast$near(val) {\n  const SchemaArray = require('../array');\n\n  if (Array.isArray(val)) {\n    castArraysOfNumbers(val, this);\n    return val;\n  }\n\n  _castMinMaxDistance(this, val);\n\n  if (val?.$geometry) {\n    return cast$geometry(val, this);\n  }\n\n  if (!Array.isArray(val)) {\n    throw new TypeError('$near must be either an array or an object ' +\n      'with a $geometry property');\n  }\n\n  return SchemaArray.prototype.castForQuery.call(this, null, val);\n}\n\nfunction cast$geometry(val, self) {\n  switch (val.$geometry.type) {\n    case 'Polygon':\n    case 'LineString':\n    case 'Point':\n      castArraysOfNumbers(val.$geometry.coordinates, self);\n      break;\n    default:\n      // ignore unknowns\n      break;\n  }\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schema/operators/geospatial.js#L15-L51","documentation":"cast$near (used by $near and $nearSphere on geospatial paths) accepts three shapes: a legacy coordinate array ([x, y]), an object with a $geometry key (GeoJSON, optionally with $maxDistance/$minDistance), or an array value handled by the array caster. Anything else — a string, a plain { lat, lng } object without $geometry, null — falls through to this TypeError.","triggerScenarios":"`Model.find({ loc: { $near: '12,34' } })` (string), `{ loc: { $near: { lat: 12, lng: 34 } } }` (missing $geometry wrapper), `{ loc: { $near: {} } }`. Note: an object with only $maxDistance/$minDistance but no $geometry also reaches the throw.","commonSituations":"Sending Google-Maps-style { lat, lng } objects instead of GeoJSON; forgetting the $geometry wrapper around GeoJSON; confusing $near query syntax with the $geoNear aggregation stage; clients sending 'lat,lng' strings from URL query params.","solutions":["Use legacy pairs: `{ loc: { $near: [lng, lat] } }` — note longitude first","Use proper GeoJSON: `{ loc: { $near: { $geometry: { type: 'Point', coordinates: [lng, lat] }, $maxDistance: 5000 } } }`","Normalize client coordinates (lat/lng objects or strings) into one of the two accepted shapes in your query-building layer","For $geoNear aggregation, use its near/distanceField options instead"],"exampleFix":"// before\nModel.find({ loc: { $near: { lat: 34.05, lng: -118.24 } } });\n\n// after\nModel.find({ loc: { $near: { $geometry: { type: 'Point', coordinates: [-118.24, 34.05] }, $maxDistance: 5000 } } });","handlingStrategy":"validation","validationCode":"function toNearFilter(coords /* { lng, lat } or [lng, lat] */, maxDistance) {\n  const point = Array.isArray(coords) ? coords : [coords.lng, coords.lat];\n  if (typeof point[0] !== 'number' || typeof point[1] !== 'number') {\n    throw new Error('$near needs [lng, lat] numbers or { $geometry }');\n  }\n  return { $near: { $geometry: { type: 'Point', coordinates: point }, $maxDistance: maxDistance } };\n}","typeGuard":"function isValidNear(v) {\n  return Array.isArray(v) || (v != null && typeof v === 'object' && v.$geometry != null);\n}","tryCatchPattern":"try { await Model.find({ loc: { $near: value } }); } catch (err) { if (/\\$near must be either an array/.test(err.message)) { return badRequest('$near requires [lng, lat] or { $geometry: ... }'); } throw err; }","preventionTips":["Normalize lat/lng client payloads into [lng, lat] at the boundary","Always wrap GeoJSON in $geometry for $near","Remember coordinate order is longitude, latitude"],"tags":["mongoose","geospatial","near","geojson","query"],"backgroundTag":"invalid-geo-query","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}