{"record":{"id":"ac7856ec51cad47b","repo":"actualbudget/actual","slug":"invalid-filter-conditionsop-filter-conditionsop","errorCode":null,"errorMessage":"Invalid filter conditionsOp: ${filter.conditionsOp}","messagePattern":"Invalid filter conditionsOp: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/filters/app.ts","lineNumber":18,"sourceCode":"// @ts-strict-ignore\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { createApp } from '#server/app';\nimport * as db from '#server/db';\nimport { requiredFields } from '#server/models';\nimport { mutator } from '#server/mutators';\nimport { parseConditionsOrActions } from '#server/transactions/transaction-rules';\nimport { undoable } from '#server/undo';\nimport type { TransactionFilterEntity } from '#types/models';\n\nconst filterModel = {\n  validate(filter, { update }: { update?: boolean } = {}) {\n    requiredFields('transaction_filters', filter, ['conditions'], update);\n\n    if (!update || 'conditionsOp' in filter) {\n      if (!['and', 'or'].includes(filter.conditionsOp)) {\n        throw new Error('Invalid filter conditionsOp: ' + filter.conditionsOp);\n      }\n    }\n\n    return filter;\n  },\n\n  toJS(row) {\n    const { conditions, conditions_op, ...fields } = row;\n    return {\n      ...fields,\n      conditionsOp: conditions_op,\n      conditions: parseConditionsOrActions(conditions),\n    };\n  },\n\n  fromJS(filter) {\n    const { conditionsOp, ...row } = filter;\n    if (conditionsOp) {","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/filters/app.ts#L1-L36","documentation":"The filter model's validate() checks that conditionsOp is exactly 'and' or 'or' (whenever it is present — always on create, only if supplied on update). Any other value, including null/undefined on create, throws 'Invalid filter conditionsOp: <value>'.","triggerScenarios":"Creating a transaction filter without conditionsOp or with a typo like 'AND'/'Any'; an update call supplying conditionsOp: null; client code building condition objects manually with an unsupported operator.","commonSituations":"Custom integrations/plugins writing filters via the API; hand-edited imports; older clients or external tools producing capitalized operators after a schema tightening.","solutions":["Set conditionsOp to 'and' or 'or' (lowercase) when creating a filter","Normalize/capitalize the operator before calling createFilter/updateFilter","On updates, omit conditionsOp entirely if unchanged instead of passing null","Validate user input at the UI layer to restrict choices to AND/OR"],"exampleFix":"// before\nawait aqlQuery.createFilter({ name: 'Big', conditions, conditionsOp: 'AND' });\n// after\nawait aqlQuery.createFilter({ name: 'Big', conditions, conditionsOp: 'and' });","handlingStrategy":"validation","validationCode":"const VALID_OPS = ['and', 'or'];\nif (!VALID_OPS.includes(filter.conditionsOp)) {\n  throw new Error(`conditionsOp must be 'and' or 'or', got '${filter.conditionsOp}'`);\n}","typeGuard":"function isValidConditionsOp(op: unknown): op is 'and' | 'or' {\n  return op === 'and' || op === 'or';\n}","tryCatchPattern":"try {\n  await aqlQuery.createFilter(filter);\n} catch (e) {\n  if (e.message.startsWith('Invalid filter conditionsOp')) {\n    filter.conditionsOp = 'and'; // sensible default\n    await aqlQuery.createFilter(filter);\n  } else throw e;\n}","preventionTips":["Always pass lowercase 'and' or 'or' exactly — no capitalization variants","On updates, omit conditionsOp rather than sending null","Build filters via shared helpers that default conditionsOp to 'and'","Normalize external/imported filter data before writing"],"tags":["validation","filters","schema","conditions"],"backgroundTag":"schema-validation-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}