actualbudget/actual · error · APIError

Failed creating a new rule

Error message

Failed creating a new rule

What it means

api.createRule() delegates to the internal rule-add handler, which validates the rule (conditions, actions, condition structure). If the internal handler returns { error }, the API wraps it in this APIError with the original error attached.

Source

Thrown at packages/loot-core/src/server/api.ts:898

  return handlers['payees-get-nearby']({ latitude, longitude, maxDistance });
};

handlers['api/rules-get'] = async function () {
  checkFileOpen();
  return handlers['rules-get']();
};

handlers['api/payee-rules-get'] = async function ({ id }) {
  checkFileOpen();
  return handlers['payees-get-rules']({ id });
};

handlers['api/rule-create'] = withMutation(async function ({ rule }) {
  checkFileOpen();
  const addedRule = await handlers['rule-add'](ruleModel.fromExternal(rule));

  if ('error' in addedRule) {
    throw APIError('Failed creating a new rule', addedRule.error);
  }

  return addedRule;
});

handlers['api/rule-update'] = withMutation(async function ({ rule }) {
  checkFileOpen();
  const updatedRule = await handlers['rule-update'](
    ruleModel.fromExternal(rule),
  );

  if ('error' in updatedRule) {
    throw APIError('Failed updating the rule', updatedRule.error);
  }

  return updatedRule;
});

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Inspect the attached addedRule.error (the APIError's cause) for the underlying validation message
  2. Build the rule object with a valid conditionOp/conditions shape per docs — verify field names and operator/value compatibility
  3. Test the same rule in the UI Rules editor; if the UI rejects it too, fix the rule, not the API call

Example fix

// before
await api.createRule({ conditions: [{ field: 'payee_name', op: 'contains', value: 123 }] });
// after
await api.createRule({ conditions: [{ field: 'payee_name', op: 'contains', value: 'Store' }], actions: [{ field: 'category', value: 'Groceries' }], operation: 'and' });
Defensive patterns

Strategy: try-catch

Validate before calling

const parsed = ruleModel.fromExternal(rule);
const res = await handlers['rule-add'](parsed);
if ('error' in res) preflightCheck(res.error);

Type guard

function isRuleError(r) {
  return r != null && typeof r === 'object' && 'error' in r;
}

Try / catch

const added = await ruleAdd(rule);
if (isRuleError(added)) {
  throw new APIError('Failed creating a new rule', added.error);
}

Prevention

When it happens

Trigger: Calling api.createRule(rule) with a rule whose conditions/actions reference unknown fields, invalid operators (e.g. wrong value type for the operator), or a malformed conditions object.

Common situations: Hand-constructed rule payloads in scripts; rules exported from an older Actual version with operators no longer supported; typos in field names like 'payee' vs 'payee_name'.

Related errors


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