{"record":{"id":"c01c120bea0900aa","repo":"Automattic/mongoose","slug":"cast-to-array-failed-for-value-value-at-path","errorCode":null,"errorMessage":"Cast to Array failed for value \"${value}\" at path \"${path}\"","messagePattern":"Cast to Array failed for value \"(.+?)\" at path \"(.+?)\"","errorType":"exception","errorClass":"CastError","httpStatus":null,"severity":"error","filePath":"lib/cast.js","lineNumber":67,"sourceCode":"  const paths = Object.keys(obj);\n  let i = paths.length;\n  let _keys;\n  let any$conditionals;\n  let schematype;\n  let nested;\n  let path;\n  let type;\n  let val;\n\n  options = options || {};\n\n  while (i--) {\n    path = paths[i];\n    val = obj[path];\n\n    if (path === '$or' || path === '$nor' || path === '$and') {\n      if (!Array.isArray(val)) {\n        throw new CastError('Array', val, path);\n      }\n      for (let k = val.length - 1; k >= 0; k--) {\n        if (val[k] == null || typeof val[k] !== 'object') {\n          throw new CastError('Object', val[k], path + '.' + k);\n        }\n        const beforeCastKeysLength = Object.keys(val[k]).length;\n        const discriminatorValue = val[k][schema.options.discriminatorKey];\n        if (discriminatorValue == null) {\n          val[k] = cast(schema, val[k], options, context);\n        } else {\n          const discriminatorSchema = getSchemaDiscriminatorByValue(context.schema, discriminatorValue);\n          val[k] = cast(discriminatorSchema ? discriminatorSchema : schema, val[k], options, context);\n        }\n\n        if (utils.hasOwnKeys(val[k]) === false && beforeCastKeysLength !== 0) {\n          val.splice(k, 1);\n        }\n      }","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/cast.js#L49-L85","documentation":"Mongoose throws this CastError while casting query conditions when a logical operator ($or, $nor, or $and) is not an Array. lib/cast.js walks every key of the conditions object and requires these operators to hold a list of sub-condition objects; any other shape fails before the query reaches MongoDB. The error carries the offending value and path (e.g. '$or') for diagnosis.","triggerScenarios":"Model.find({ $or: { a: 1 } }) -- a single condition object instead of an array of them; { $and: 'x' }; { $nor: { a: 1, b: 2 } }; filters built from JSON request bodies or querystrings where $or arrives as an object.","commonSituations":"Dynamic query builders that assign instead of push; clients serializing $or as an object; refactors that drop the array brackets; comma-separated strings that were never split into condition objects.","solutions":["Pass an array of condition objects: Model.find({ $or: [{ name: 'foo' }, { age: { $gte: 21 } }] })","In dynamic builders, always push whole condition objects: conds.push({ field: value })","Validate incoming filter payloads so $or/$and/$nor are arrays of objects before they reach mongoose"],"exampleFix":"// before\nModel.find({ $or: { name: 'foo', age: { $gte: 21 } } });\n\n// after\nModel.find({ $or: [{ name: 'foo' }, { age: { $gte: 21 } }] });","handlingStrategy":"validation","validationCode":"function assertLogicalOpsAreArrays(q) {\n  for (const key of ['$or', '$and', '$nor']) {\n    if (q[key] === undefined) continue;\n    if (!Array.isArray(q[key])) {\n      throw new TypeError(`${key} must be an array of condition objects`);\n    }\n    q[key].forEach((c, i) => {\n      if (c == null || typeof c !== 'object') {\n        throw new TypeError(`${key}[${i}] must be an object`);\n      }\n    });\n  }\n  return q;\n}\n\nawait Model.find(assertLogicalOpsAreArrays(req.query));","typeGuard":"function isWellFormedLogicalQuery(q) {\n  return ['$or', '$and', '$nor'].every(k =>\n    q[k] === undefined ||\n    (Array.isArray(q[k]) && q[k].every(c => c != null && typeof c === 'object'))\n  );\n}","tryCatchPattern":"try {\n  const docs = await Model.find(query);\n} catch (err) {\n  if (err.name === 'CastError' && err.kind === 'Array') {\n    // err.path names the operator ('$or'/'$and'/'$nor'); rebuild it as [{...}, {...}]\n  }\n  throw err;\n}","preventionTips":["Always write $or/$and/$nor as arrays of objects, even with a single condition: { $or: [{ a: 1 }] }","Never pass raw client JSON directly as a filter; map whitelisted fields into a known shape first","Centralize logical-operator construction in one query-builder module"],"tags":["mongoose","query","cast","logical-operators"],"backgroundTag":"query-cast-failed","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}