{"record":{"id":"272775cf93e0feff","repo":"krisk/Fuse","slug":"unknown-query-operator-op","errorCode":null,"errorMessage":"Unknown query operator '${op}'","messagePattern":"Unknown query operator '(.+?)'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/search/extended/objectQuery.ts","lineNumber":110,"sourceCode":"        )\n      }\n\n      const innerOp = innerOps[0]\n      if (innerOp === NOT) {\n        throw new Error(\n          ErrorMsg.INVALID_FIELD_QUERY(keyPath, '$not cannot be nested')\n        )\n      }\n      if (innerOp === AND || innerOp === OR) {\n        throw new Error(\n          ErrorMsg.INVALID_FIELD_QUERY(\n            keyPath,\n            `${innerOp} cannot be used inside $not`\n          )\n        )\n      }\n      if (!isKnownOperator(innerOp)) {\n        throw new Error(ErrorMsg.UNKNOWN_QUERY_OPERATOR(innerOp))\n      }\n\n      // `$fuzzy` and `$eq` have no inverse matcher (fuzzy is graded rather than\n      // boolean; whole-string inequality is unimplemented, which is why `$ne`\n      // stays reserved). Report that distinctly from \"unknown operator\".\n      def = negatedMatcherDefForOperator(innerOp)\n      if (!def) {\n        throw new Error(\n          ErrorMsg.INVALID_FIELD_QUERY(\n            keyPath,\n            `'${innerOp}' cannot be negated`\n          )\n        )\n      }\n\n      raw = inner[innerOp]\n      valueOp = innerOp\n    } else {","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/krisk/Fuse/blob/edf2fb608eca0461508d1d71317e6e58309ffada/src/search/extended/objectQuery.ts#L92-L128","documentation":"The operator wrapped by $not must be a known operator. When isKnownOperator(innerOp) is false, compileClause throws UNKNOWN_QUERY_OPERATOR with the inner operator's name. This is the negation-path check before an inverse matcher is looked up.","triggerScenarios":"search({ title: { $not: { $contins: 'a' } } }) — a typo'd or entirely unknown operator inside $not.","commonSituations":"Typos in operator names ($regex vs $regexx); using operators from another library (Mongo's $gte/$lte are not supported here); refactors that renamed operators while queries were stored as strings/config.","solutions":["Fix the operator name inside $not to a supported one ($contains, $startsWith, $endsWith, $fuzzy, $eq, etc.)","Check the library docs for the supported operator list — Mongo operators like $gt/$in are not available","If queries come from persisted config, validate operator names against isKnownOperator before calling search"],"exampleFix":"// before\nsearch({ title: { $not: { $gte: 'a' } } })\n// after\nsearch({ title: { $not: { $startsWith: 'a' } } })","handlingStrategy":"type-guard","validationCode":"import { isKnownOperator } from './search/extended/matchers'\nfunction validateNegatedOperator(clause) {\n  const inner = clause && clause.$not\n  if (inner) {\n    const op = Object.keys(inner)[0]\n    if (!isKnownOperator(op)) throw new Error(`Unknown operator '${op}' inside $not`)\n  }\n}","typeGuard":"function isKnownOperator(op) { return KNOWN_OPS.includes(op) }","tryCatchPattern":"try {\n  results = search(query)\n} catch (e) {\n  if (e.message.includes('Unknown query operator')) {\n    const op = e.message.match(/'([^']+)'/)?.[1]\n    throw new Error(`'${op}' is not supported — check the operator list (typos? Mongo ops?)`)\n  } else throw e\n}","preventionTips":["Check operator names against the documented list","Watch for Mongo/SQL operator leakage ($gte, $in, LIKE) into queries","Validate persisted query configs after any library upgrade"],"tags":["query-grammar","unknown-operator","negation"],"backgroundTag":"unknown-query-operator","analyzedSha":"edf2fb608eca0461508d1d71317e6e58309ffada","analyzedAt":"2026-09-02T02:46:54.623Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}