{"record":{"id":"7a85f8fd63477d63","repo":"actualbudget/actual","slug":"unknown-operator-op","errorCode":null,"errorMessage":"Unknown operator: ${op}","messagePattern":"Unknown operator: (.+?)","errorType":"exception","errorClass":"CompileError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/compiler.ts","lineNumber":746,"sourceCode":"        `${String(left)} IN (` +\n        ids.map(id => `'${String(id)}'`).join(',') +\n        ')'\n      );\n    }\n    case '$like': {\n      const [left, right] = valArray(state, [lhs, rhs], ['string', 'string']);\n      return `UNICODE_LIKE(${getNormalisedString(right)}, NORMALISE(${left}))`;\n    }\n    case '$regexp': {\n      const [left, right] = valArray(state, [lhs, rhs], ['string', 'string']);\n      return `REGEXP(${right}, ${left})`;\n    }\n    case '$notlike': {\n      const [left, right] = valArray(state, [lhs, rhs], ['string', 'string']);\n      return `(NOT UNICODE_LIKE(${getNormalisedString(right)}, NORMALISE(${left}))\\n OR ${left} IS NULL)`;\n    }\n    default:\n      throw new CompileError(`Unknown operator: ${op}`);\n  }\n});\n\nfunction compileConditions(state, conds) {\n  if (!Array.isArray(conds)) {\n    // Convert the object form `{foo: 1, bar:2}` into the array form\n    // `[{foo: 1}, {bar:2}]`\n    conds = Object.entries(conds).map(cond => {\n      return { [cond[0]]: cond[1] };\n    });\n  }\n\n  return conds.filter(Boolean).reduce((res, condsObj) => {\n    const compiled = Object.entries(condsObj)\n      .map(([field, cond]) => {\n        // Allow a falsy value in the lhs of $and and $or to allow for\n        // quick forms like `$or: amount != 0 && ...`\n        if (field === '$and') {","sourceCodeStart":728,"sourceCodeEnd":764,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/compiler.ts#L728-L764","documentation":"compileOp dispatches on the filter operator key of an AQL condition (`$eq`, `$like`, `$notlike`, ...) and throws CompileError in its `default` branch when the operator is unrecognized. The query cannot be translated to SQL because the operator has no mapping.","triggerScenarios":"Building a filter like `{amount: {$greaterThan: 100}}` with a misspelled or unsupported operator name, or using an operator that was renamed in a newer AQL version.","commonSituations":"Typos such as `$gt`/`$>` borrowed from other query languages (Mongo/GraphQL-style operators) that AQL does not support, or docs from an older version listing removed operators.","solutions":["Check compiler.ts compileOp for the exact supported operator names and correct the key (e.g. `$gte`, `$lt`, `$like`, `$notlike`).","Replace Mongo-style operators (`$gt`, `$ne`, `$in`) with the AQL equivalents.","If migrating from an older version, review the changelog for renamed operators."],"exampleFix":"// before\n{amount: {$gt: 100}}\n// after\n{amount: {$gt_: 100}} // or the actual supported operator, e.g. {$gt: 100} -> {$gte: 100} style keys defined in compileOp","handlingStrategy":"validation","validationCode":"const KNOWN_OPS = new Set(['$eq', '$ne', '$lt', '$lte', '$gt', '$gte', '$like', '$notlike', '$oneof', '$in', ...]);\nfunction assertKnownOp(op) {\n  if (!KNOWN_OPS.has(op)) throw new Error(`Unknown AQL operator: ${op}`);\n}","typeGuard":"const isKnownOp = (op) => typeof op === 'string' && KNOWN_OPS.has(op);","tryCatchPattern":null,"preventionTips":["Translate Mongo/SQL operator habits to AQL names once in a helper layer.","Type filter objects with a union of valid operator keys.","Test each filter operator against a real query in CI."],"tags":["aql","query-compiler","unknown-operator"],"backgroundTag":"unknown-operator","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}