actualbudget/actual · error · ValidationError
Invalid filter conditionsOp: ${report.conditionsOp}
Error message
Invalid filter conditionsOp: ${report.conditionsOp} What it means
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).
Source
Thrown at packages/loot-core/src/server/reports/app.ts:22
import { aqlQuery } from '#server/aql';
import * as db from '#server/db';
import { ValidationError } from '#server/errors';
import { requiredFields } from '#server/models';
import { mutator } from '#server/mutators';
import { undoable } from '#server/undo';
import { q } from '#shared/query';
import type { CustomReportData, CustomReportEntity } from '#types/models';
export const reportModel = {
validate(
report: Omit<CustomReportEntity, 'tombstone'>,
{ update }: { update?: boolean } = {},
) {
requiredFields('Report', report, ['conditionsOp'], update);
if (!update || 'conditionsOp' in report) {
if (!['and', 'or'].includes(report.conditionsOp)) {
throw new ValidationError(
'Invalid filter conditionsOp: ' + report.conditionsOp,
);
}
}
return report;
},
toJS(row: CustomReportData): CustomReportEntity {
return {
id: row.id,
name: row.name ?? '',
startDate: row.start_date,
endDate: row.end_date,
isDateStatic: row.date_static === 1,
dateRange: row.date_range,
mode: row.mode,
groupBy: row.group_by,View on GitHub (pinned to d4334cb6e6)
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
Example fix
// before
const report = { name: 'Groceries', conditions, conditionsOp: 'AND' };
await app.createReport(report);
// after
const report = { name: 'Groceries', conditions, conditionsOp: 'and' };
await app.createReport(report); Defensive patterns
Strategy: validation
Validate before calling
const VALID_OPS = ['and', 'or'] as const;
function isValidConditionsOp(v: unknown): v is 'and' | 'or' {
return typeof v === 'string' && (VALID_OPS as readonly string[]).includes(v);
}
if (!isValidConditionsOp(report.conditionsOp)) {
throw new Error(`conditionsOp must be 'and' or 'or', got: ${report.conditionsOp}`);
} Type guard
function isValidConditionsOp(value: unknown): value is 'and' | 'or' {
return value === 'and' || value === 'or';
} Try / catch
try {
await app.createReport(report);
} catch (err) {
if (err instanceof ValidationError && err.message.startsWith('Invalid filter conditionsOp')) {
report.conditionsOp = 'and'; // safe default
await app.createReport(report);
} else {
throw err;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Unknown payee name normalization: ${String(normalization)}
- Report name is required
- There is already a report named ${item.name}
- transactions-import: accountId must be an id
- Invalid --name: must be a non-empty string.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/3a08a34f465ba09e.
Report an issue: GitHub.