Automattic/mongoose · error · Error
Can't use ${conditional}
Error message
Can't use ${conditional} What it means
Single-nested paths support a limited operator set in query casting: the base handlers ($eq, $in, $ne, $nin, $all, $exists, $type) plus geospatial ones ($geoWithin, $near, $nearSphere, $within, $geoIntersects, $minDistance, $maxDistance). Using any other operator directly on the subdocument path makes SchemaSubdocument.castForQuery throw this error while the query is built.
Source
Thrown at lib/schema/subdocument.js:240
}
return subdoc;
};
/**
* Casts contents for query
*
* @param {string} [$conditional] optional query operator (like `$eq` or `$in`)
* @param {any} value
* @api private
*/
SchemaSubdocument.prototype.castForQuery = function($conditional, val, context, options) {
let handler;
if ($conditional != null) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional);
}
return handler.call(this, val);
}
if (val == null) {
return val;
}
const Constructor = getConstructor(this.Constructor, val);
if (val instanceof Constructor) {
return val;
}
if (this.options.runSetters) {
val = this._applySetters(val, context);
}
const overrideStrict = options?.strict ?? void 0;
View on GitHub (pinned to 49cdab0136)
Solutions
- Target the subfield with a dotted path: `Model.find({ 'address.city': /San/ })`
- Use `$elemMatch` when querying arrays of subdocuments
- For whole-document equality use `$eq` with a plain object of the subdocument's values
Example fix
// before
Model.find({ address: { $regex: /San/ } }); // throws: Can't use $regex
// after
Model.find({ 'address.city': /San/ }); Defensive patterns
Strategy: validation
Validate before calling
const SUBDOC_OPS = new Set(['$eq','$in','$ne','$nin','$all','$exists','$type','$geoWithin','$geoIntersects','$near','$nearSphere','$within','$minDistance','$maxDistance']);
function assertSubdocOp(op) {
if (!SUBDOC_OPS.has(op)) throw new Error(`operator ${op} is not supported on subdocument paths; query subfields with dotted paths`);
} Type guard
const isSupportedSubdocOp = op => SUBDOC_OPS.has(op);
Try / catch
try {
await Model.find({ nested: { [op]: val } });
} catch (err) {
if (/^Can't use \$/.test(err.message)) {
// rewrite the filter to use a dotted subfield path and retry once
} else throw err;
} Prevention
- Prefer dotted paths ('address.city') over operator objects on the embedded path itself
- Schema-aware filter builders should know each path's resolved type before attaching operators
When it happens
Trigger: `Model.find({ nested: { $size: 2 } })`; `Model.find({ address: { $regex: /San/ } })` where `address` is an embedded schema; `{ nested: { $gt: { ... } } }`.
Common situations: Generic filter builders applying operators to every path; trying to regex-match or range-compare a whole embedded object instead of its subfield.
Related errors
- Can't use ${conditional} with String.
- Cast to Embedded failed for value "${value}" (type ${valueTy
- Can't use ${conditional} with UUID.
- Can't use ${conditional}
- Invalid addFields() argument. Must be an object
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/aa6f008dc8dec2fe.
Report an issue: GitHub.