{"record":{"id":"3a08a34f465ba09e","repo":"actualbudget/actual","slug":"invalid-filter-conditionsop-report-conditionsop","errorCode":null,"errorMessage":"Invalid filter conditionsOp: ${report.conditionsOp}","messagePattern":"Invalid filter conditionsOp: (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/reports/app.ts","lineNumber":22,"sourceCode":"import { aqlQuery } from '#server/aql';\nimport * as db from '#server/db';\nimport { ValidationError } from '#server/errors';\nimport { requiredFields } from '#server/models';\nimport { mutator } from '#server/mutators';\nimport { undoable } from '#server/undo';\nimport { q } from '#shared/query';\nimport type { CustomReportData, CustomReportEntity } from '#types/models';\n\nexport const reportModel = {\n  validate(\n    report: Omit<CustomReportEntity, 'tombstone'>,\n    { update }: { update?: boolean } = {},\n  ) {\n    requiredFields('Report', report, ['conditionsOp'], update);\n\n    if (!update || 'conditionsOp' in report) {\n      if (!['and', 'or'].includes(report.conditionsOp)) {\n        throw new ValidationError(\n          'Invalid filter conditionsOp: ' + report.conditionsOp,\n        );\n      }\n    }\n\n    return report;\n  },\n\n  toJS(row: CustomReportData): CustomReportEntity {\n    return {\n      id: row.id,\n      name: row.name ?? '',\n      startDate: row.start_date,\n      endDate: row.end_date,\n      isDateStatic: row.date_static === 1,\n      dateRange: row.date_range,\n      mode: row.mode,\n      groupBy: row.group_by,","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/reports/app.ts#L4-L40","documentation":"A ValidationError thrown by reportModel.validate when the custom report's conditionsOp field is not exactly 'and' or 'or'. conditionsOp defines how report filter conditions are combined (logical AND/OR), and the model enforces this closed set on both create and update (whenever conditionsOp is present).","triggerScenarios":"Passing a report object to createReport/updateReport (or report-model-driven validation) with conditionsOp missing on create, undefined/null, a different case ('AND'), a localized value, or any string outside ['and','or'] — e.g. deserializing a report from untrusted JSON or an older/foreign schema.","commonSituations":"Importing custom reports from external tools or hand-edited backups where conditionsOp was 'AND' or omitted; API scripts building report payloads with a boolean instead of the string; version changes where an old client sent legacy operator names.","solutions":["Set conditionsOp to the lowercase string 'and' or 'or' in the report payload before calling the API","Default the value when constructing payloads: conditionsOp: report.conditionsOp ?? 'and'","Normalize/trim/lowercase any externally supplied operator before validation","Inspect the payload with a log or debugger to see the exact offending value appended to the message"],"exampleFix":"// before\nconst report = { name: 'Groceries', conditions, conditionsOp: 'AND' };\nawait app.createReport(report);\n// after\nconst report = { name: 'Groceries', conditions, conditionsOp: 'and' };\nawait app.createReport(report);","handlingStrategy":"validation","validationCode":"const VALID_OPS = ['and', 'or'] as const;\nfunction isValidConditionsOp(v: unknown): v is 'and' | 'or' {\n  return typeof v === 'string' && (VALID_OPS as readonly string[]).includes(v);\n}\nif (!isValidConditionsOp(report.conditionsOp)) {\n  throw new Error(`conditionsOp must be 'and' or 'or', got: ${report.conditionsOp}`);\n}","typeGuard":"function isValidConditionsOp(value: unknown): value is 'and' | 'or' {\n  return value === 'and' || value === 'or';\n}","tryCatchPattern":"try {\n  await app.createReport(report);\n} catch (err) {\n  if (err instanceof ValidationError && err.message.startsWith('Invalid filter conditionsOp')) {\n    report.conditionsOp = 'and'; // safe default\n    await app.createReport(report);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Always default conditionsOp to 'and' when building report payloads","Never pass user-supplied operator strings without normalizing to lowercase","Validate the full report entity against the CustomReportEntity type before API calls","When importing report JSON, map legacy operator names ('AND'/'OR') to lowercase"],"tags":["validation","custom-reports","typescript"],"backgroundTag":"schema-validation-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}