Automattic/mongoose · error · CastError
Cast to Array failed for value "${value}" at path "${path}"
Error message
Cast to Array failed for value "${value}" at path "${path}" What it means
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.
Source
Thrown at lib/cast.js:67
const paths = Object.keys(obj);
let i = paths.length;
let _keys;
let any$conditionals;
let schematype;
let nested;
let path;
let type;
let val;
options = options || {};
while (i--) {
path = paths[i];
val = obj[path];
if (path === '$or' || path === '$nor' || path === '$and') {
if (!Array.isArray(val)) {
throw new CastError('Array', val, path);
}
for (let k = val.length - 1; k >= 0; k--) {
if (val[k] == null || typeof val[k] !== 'object') {
throw new CastError('Object', val[k], path + '.' + k);
}
const beforeCastKeysLength = Object.keys(val[k]).length;
const discriminatorValue = val[k][schema.options.discriminatorKey];
if (discriminatorValue == null) {
val[k] = cast(schema, val[k], options, context);
} else {
const discriminatorSchema = getSchemaDiscriminatorByValue(context.schema, discriminatorValue);
val[k] = cast(discriminatorSchema ? discriminatorSchema : schema, val[k], options, context);
}
if (utils.hasOwnKeys(val[k]) === false && beforeCastKeysLength !== 0) {
val.splice(k, 1);
}
}View on GitHub (pinned to 49cdab0136)
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
Example fix
// before
Model.find({ $or: { name: 'foo', age: { $gte: 21 } } });
// after
Model.find({ $or: [{ name: 'foo' }, { age: { $gte: 21 } }] }); Defensive patterns
Strategy: validation
Validate before calling
function assertLogicalOpsAreArrays(q) {
for (const key of ['$or', '$and', '$nor']) {
if (q[key] === undefined) continue;
if (!Array.isArray(q[key])) {
throw new TypeError(`${key} must be an array of condition objects`);
}
q[key].forEach((c, i) => {
if (c == null || typeof c !== 'object') {
throw new TypeError(`${key}[${i}] must be an object`);
}
});
}
return q;
}
await Model.find(assertLogicalOpsAreArrays(req.query)); Type guard
function isWellFormedLogicalQuery(q) {
return ['$or', '$and', '$nor'].every(k =>
q[k] === undefined ||
(Array.isArray(q[k]) && q[k].every(c => c != null && typeof c === 'object'))
);
} Try / catch
try {
const docs = await Model.find(query);
} catch (err) {
if (err.name === 'CastError' && err.kind === 'Array') {
// err.path names the operator ('$or'/'$and'/'$nor'); rebuild it as [{...}, {...}]
}
throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cast to Object failed for value "${value}" at path "${path}.
- Query filter must be an object, got an array ${util.inspect(
- Cast to number failed for value "${value}" (type ${valueType
- Cast to $text failed for value "${value}" (type ${valueType}
- Cast to string failed for value "${value}" (type ${valueType
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/c01c120bea0900aa.
Report an issue: GitHub.