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
- Set amountOp to exactly one of 'is', 'isapprox', or 'isbetween'.
- If you meant a range, use 'isbetween' and provide an array value for the amount field.
- 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
- Keep the operator list ('is','isapprox','isbetween') in a shared constant
- Never pass UI-specific operator names straight through
- Type amountOp as the union type in your integration code
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
- There is already a schedule named: ${newName}
- Field ${typedKey} is system-managed and not user-editable.
- Unknown payee name normalization: ${String(normalization)}
- `date` is required when adding a transaction
- Amount is invalid, must be an integer: ${trans.amount}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/4e0ae3c295db1721.
Report an issue: GitHub.