actualbudget/actual · error

Invalid filter conditionsOp: ${filter.conditionsOp}

Error message

Invalid filter conditionsOp: ${filter.conditionsOp}

What it means

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>'.

Source

Thrown at packages/loot-core/src/server/filters/app.ts:18

// @ts-strict-ignore
import { v4 as uuidv4 } from 'uuid';

import { createApp } from '#server/app';
import * as db from '#server/db';
import { requiredFields } from '#server/models';
import { mutator } from '#server/mutators';
import { parseConditionsOrActions } from '#server/transactions/transaction-rules';
import { undoable } from '#server/undo';
import type { TransactionFilterEntity } from '#types/models';

const filterModel = {
  validate(filter, { update }: { update?: boolean } = {}) {
    requiredFields('transaction_filters', filter, ['conditions'], update);

    if (!update || 'conditionsOp' in filter) {
      if (!['and', 'or'].includes(filter.conditionsOp)) {
        throw new Error('Invalid filter conditionsOp: ' + filter.conditionsOp);
      }
    }

    return filter;
  },

  toJS(row) {
    const { conditions, conditions_op, ...fields } = row;
    return {
      ...fields,
      conditionsOp: conditions_op,
      conditions: parseConditionsOrActions(conditions),
    };
  },

  fromJS(filter) {
    const { conditionsOp, ...row } = filter;
    if (conditionsOp) {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Set conditionsOp to 'and' or 'or' (lowercase) when creating a filter
  2. Normalize/capitalize the operator before calling createFilter/updateFilter
  3. On updates, omit conditionsOp entirely if unchanged instead of passing null
  4. Validate user input at the UI layer to restrict choices to AND/OR

Example fix

// before
await aqlQuery.createFilter({ name: 'Big', conditions, conditionsOp: 'AND' });
// after
await aqlQuery.createFilter({ name: 'Big', conditions, conditionsOp: 'and' });
Defensive patterns

Strategy: validation

Validate before calling

const VALID_OPS = ['and', 'or'];
if (!VALID_OPS.includes(filter.conditionsOp)) {
  throw new Error(`conditionsOp must be 'and' or 'or', got '${filter.conditionsOp}'`);
}

Type guard

function isValidConditionsOp(op: unknown): op is 'and' | 'or' {
  return op === 'and' || op === 'or';
}

Try / catch

try {
  await aqlQuery.createFilter(filter);
} catch (e) {
  if (e.message.startsWith('Invalid filter conditionsOp')) {
    filter.conditionsOp = 'and'; // sensible default
    await aqlQuery.createFilter(filter);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Custom integrations/plugins writing filters via the API; hand-edited imports; older clients or external tools producing capitalized operators after a schema tightening.

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/ac7856ec51cad47b. Report an issue: GitHub.