{"record":{"id":"510af2a04235ec94","repo":"Automattic/mongoose","slug":"can-t-use-conditional-with-date","errorCode":null,"errorMessage":"Can't use ${$conditional} with Date.","messagePattern":"Can't use (.+?) with Date\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/schema/date.js","lineNumber":441,"sourceCode":" * @api private\n */\n\nSchemaDate.prototype.castForQuery = function($conditional, val, context) {\n  if ($conditional == null) {\n    try {\n      return this.applySetters(val, context);\n    } catch (err) {\n      if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {\n        err.path = this.$fullPath;\n      }\n      throw err;\n    }\n  }\n\n  const handler = this.$conditionalHandlers[$conditional];\n\n  if (!handler) {\n    throw new Error('Can\\'t use ' + $conditional + ' with Date.');\n  }\n\n  return handler.call(this, val);\n};\n\n/**\n * Returns this schema type's representation in a JSON schema.\n *\n * @param {object} [options]\n * @param {boolean} [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.\n * @returns {object} JSON schema properties\n */\n\nSchemaDate.prototype.toJSONSchema = function toJSONSchema(options) {\n  return this._createJSONSchemaTypeDefinition('string', 'date', options);\n};\n\nSchemaDate.prototype.autoEncryptionType = function autoEncryptionType() {","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schema/date.js#L423-L459","documentation":"castForQuery on a Date path throws a plain Error when the filter uses an operator with no registered handler. Date supports $gt/$gte/$lt/$lte plus the base SchemaType handlers ($in, $nin, $ne, $exists, ...); operators like $regex, $mod, $all, or a typo'd operator reach the guard.","triggerScenarios":"`Model.find({ createdAt: { $regex: '^2024' } })`, `Model.find({ d: { $size: 2 } })`, or any `{ <datePath>: { $<op>: ... } }` where $op is not in SchemaDate's $conditionalHandlers. Date-range aggregations accidentally putting $expr-style operators inside a path filter also hit it.","commonSituations":"Copy-pasting a String-path regex filter onto a timestamp field; dynamic search UIs that offer 'contains' for every field including dates; typo'd operators ($gte vs $gt); sift.js-style operators ($between) sent straight to MongoDB paths.","solutions":["Use range operators for dates: `{ createdAt: { $gte: from, $lte: to } }`","For string matching on dates, project a formatted string (aggregation `$dateToString`) or store a separate string field","Whitelist operators per field type in dynamic query builders","Catch the Error and map it to a 400 with the offending operator name"],"exampleFix":"// before\nModel.find({ createdAt: { $regex: '^2024-01' } });\n\n// after\nModel.find({ createdAt: { $gte: new Date('2024-01-01'), $lt: new Date('2024-02-01') } });","handlingStrategy":"validation","validationCode":"const DATE_OPS = new Set(['$gt','$gte','$lt','$lte','$in','$nin','$ne','$eq','$exists','$not']);\nfunction assertDateOpsSafe(pathFilter, path) {\n  for (const op of Object.keys(pathFilter ?? {})) {\n    if (op.startsWith('$') && !DATE_OPS.has(op)) throw new Error(`operator ${op} not allowed on date path ${path}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try { await Model.find(filter); } catch (err) { if (/Can't use .* with Date/.test(err.message)) { throw Object.assign(new Error(`unsupported date operator: ${err.message}`), { status: 400 }); } throw err; }","preventionTips":["Offer only range filters for date fields in search UIs","Convert date-regex intents into $gte/$lte ranges","Test dynamic filter endpoints against every field type"],"tags":["mongoose","date","query","operator","filter"],"backgroundTag":"unsupported-query-operator","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}