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

  1. Set conditionsOp to the lowercase string 'and' or 'or' in the report payload before calling the API
  2. Default the value when constructing payloads: conditionsOp: report.conditionsOp ?? 'and'
  3. Normalize/trim/lowercase any externally supplied operator before validation
  4. 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

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/3a08a34f465ba09e. Report an issue: GitHub.