Automattic/mongoose · error · CastError
Cast to Object failed for value "${value}" at path "${path}.
Error message
Cast to Object failed for value "${value}" at path "${path}.${k}" What it means
Every element of a $or/$and/$nor array must be a condition object. lib/cast.js iterates the array and throws this CastError when an entry is null/undefined or a non-object primitive (string, number, boolean). The path in the message includes the bad index (e.g. '$and.2') so you can locate the entry.
Source
Thrown at lib/cast.js:71
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);
}
}
// delete empty: {$or: []} -> {}
if (val.length === 0) {
delete obj[path];View on GitHub (pinned to 49cdab0136)
Solutions
- Remove null/non-object entries before querying: conds.filter(c => c && typeof c === 'object')
- Only push a condition when it exists: if (name) conds.push({ name })
- Wrap raw values in a condition object when that is the intent: conds.push({ field: value })
Example fix
// before
const conds = [];
if (name) conds.push({ name });
conds.push(null); // placeholder never removed
Model.find({ $or: conds });
// after
const conds = [];
if (name) conds.push({ name });
Model.find({ $or: conds }); Defensive patterns
Strategy: validation
Validate before calling
function sanitizeLogicalOps(q) {
for (const key of ['$or', '$and', '$nor']) {
if (Array.isArray(q[key])) {
q[key] = q[key].filter(c => c != null && typeof c === 'object');
}
}
return q;
}
await Model.find(sanitizeLogicalOps(query)); Type guard
function hasOnlyObjectConditions(q) {
return ['$or', '$and', '$nor'].every(k =>
!Array.isArray(q[k]) || q[k].every(c => c != null && typeof c === 'object')
);
} Try / catch
try {
await Model.find(query);
} catch (err) {
if (err.name === 'CastError' && err.kind === 'Object' && /^\$(or|and|nor)\./.test(err.path)) {
// err.path looks like '$and.1' -> drop or fix that element and rebuild the query
}
throw err;
} Prevention
- Never push null placeholders into condition arrays
- Filter condition arrays through a truthy-object check right before the query
- Log the raw condition array when a dynamic query fails so bad entries are visible
When it happens
Trigger: Model.find({ $and: [null] }); { $or: ['name'] }; { $and: [42] }; condition arrays assembled by pushing raw values (conds.push('age > 5')) or left with holes after delete conds[i].
Common situations: Optional-filter builders that push placeholders and never clean them (arr.push(cond || null)); JSON payloads containing null entries; conditions assembled from user text instead of objects; spreading undefined into arrays.
Related errors
- Cast to Array 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/2cc0f7b44fff5aa4.
Report an issue: GitHub.