actualbudget/actual · error · APIError

Invalid amount operator: ${String(value)}. Expected: is, isa

Error message

Invalid amount operator: ${String(value)}. Expected: is, isapprox, or isbetween

What it means

When updating a schedule via the API, the 'amountOp' field must be one of the literal strings 'is', 'isapprox', or 'isbetween'. The handler switches on the provided value and throws this APIError in the default branch for anything else. It protects the schedule rule engine from invalid comparison operators.

Source

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

          conditionsUpdated = true;
        }
        break;
      }
      case 'amountOp': {
        if (amountIndex !== -1) {
          let convertedOp: AmountOPType;
          switch (value) {
            case 'is':
              convertedOp = 'is';
              break;
            case 'isapprox':
              convertedOp = 'isapprox';
              break;
            case 'isbetween':
              convertedOp = 'isbetween';
              break;
            default:
              throw APIError(
                `Invalid amount operator: ${String(value)}. Expected: is, isapprox, or isbetween`,
              );
          }
          sched._conditions[amountIndex].op = convertedOp;
          conditionsUpdated = true;
        } else {
          throw APIError(`Ammount can not be found. There is a bug here`);
        }
        break;
      }
      case 'amount': {
        if (amountIndex !== -1) {
          sched._conditions[amountIndex].value = value;
          conditionsUpdated = true;
        } else {
          throw APIError(`Ammount can not be found. There is a bug here`);
        }
        break;

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Set amountOp to exactly one of 'is', 'isapprox', or 'isbetween'.
  2. If you meant a range, use 'isbetween' and provide an array value for the amount field.
  3. Validate the operator string against the allowed list before calling the API.

Example fix

// before
await updateSchedule(id, { amountOp: 'between' });
// after
await updateSchedule(id, { amountOp: 'isbetween' });
Defensive patterns

Strategy: validation

Validate before calling

const OPS = ['is', 'isapprox', 'isbetween'];
if (!OPS.includes(op)) throw new Error(`amountOp must be one of ${OPS.join(', ')}`);
await updateSchedule(id, { amountOp: op });

Type guard

function isAmountOp(v) {
  return v === 'is' || v === 'isapprox' || v === 'isbetween';
}

Try / catch

try {
  await actual.updateSchedule(id, { amountOp: op });
} catch (e) {
  if (String(e.message).startsWith('Invalid amount operator')) {
    console.error('Bad operator:', op);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the schedule update API (e.g. api.updateSchedule / handlers['api/schedule-update']) with fields.amountOp set to anything other than 'is', 'isapprox', or 'isbetween' (including typos like 'between', 'approx', null, or numbers).

Common situations: Passing a UI-specific operator name ('equals', '~', 'between'), forgetting that 'isbetween' is one word, or programmatically building the fields object with an undefined amountOp.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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