actualbudget/actual · error · APIError

Failed updating the rule

Error message

Failed updating the rule

What it means

api.updateRule() pushes the converted rule through the internal rule-update handler. When that handler returns { error } (rule not found or invalid content), the API throws this APIError carrying the underlying error.

Source

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

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;
});

handlers['api/rule-delete'] = withMutation(async function (id) {
  checkFileOpen();
  return handlers['rule-delete'](id);
});

handlers['api/schedules-get'] = async function () {
  checkFileOpen();
  const { data } = await aqlQuery(q('schedules').select('*'));
  const schedules = data as ScheduleEntity[];
  return schedules.map(schedule => scheduleModel.toExternal(schedule));
};

handlers['api/schedule-create'] = withMutation(async function (

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Confirm the rule id exists via api.getRules() before updating
  2. Check the APIError's cause for the underlying validation failure and correct the conditions/actions
  3. Re-fetch the rule with a fresh get and modify its fields rather than reusing cached payloads

Example fix

// before
await api.updateRule(cachedRule);
// after
const rules = await api.getRules();
const fresh = rules.find(r => r.id === cachedRule.id);
if (fresh) await api.updateRule({ ...fresh, ...changes });
Defensive patterns

Strategy: try-catch

Validate before calling

const parsed = ruleModel.fromExternal(rule);
const res = await handlers['rule-update'](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 updated = await ruleUpdate(rule);
if (isRuleError(updated)) {
  throw new APIError('Failed updating the rule', updated.error);
}

Prevention

When it happens

Trigger: Calling api.updateRule(rule) with a rule id that doesn't exist in the budget, or with conditions/actions failing validation (unknown fields, bad operators, empty actions).

Common situations: Updating a rule from a stale id after the budget was re-imported/rolled back; mutating a rule fetched in a previous session before a file switch; same validation pitfalls as rule creation.

Related errors


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