{"record":{"id":"4e0ae3c295db1721","repo":"actualbudget/actual","slug":"invalid-amount-operator-string-value-expecte","errorCode":null,"errorMessage":"Invalid amount operator: ${String(value)}. Expected: is, isapprox, or isbetween","messagePattern":"Invalid amount operator: (.+?)\\. Expected: is, isapprox, or isbetween","errorType":"validation","errorClass":"APIError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/api.ts","lineNumber":1034,"sourceCode":"          conditionsUpdated = true;\n        }\n        break;\n      }\n      case 'amountOp': {\n        if (amountIndex !== -1) {\n          let convertedOp: AmountOPType;\n          switch (value) {\n            case 'is':\n              convertedOp = 'is';\n              break;\n            case 'isapprox':\n              convertedOp = 'isapprox';\n              break;\n            case 'isbetween':\n              convertedOp = 'isbetween';\n              break;\n            default:\n              throw APIError(\n                `Invalid amount operator: ${String(value)}. Expected: is, isapprox, or isbetween`,\n              );\n          }\n          sched._conditions[amountIndex].op = convertedOp;\n          conditionsUpdated = true;\n        } else {\n          throw APIError(`Ammount can not be found. There is a bug here`);\n        }\n        break;\n      }\n      case 'amount': {\n        if (amountIndex !== -1) {\n          sched._conditions[amountIndex].value = value;\n          conditionsUpdated = true;\n        } else {\n          throw APIError(`Ammount can not be found. There is a bug here`);\n        }\n        break;","sourceCodeStart":1016,"sourceCodeEnd":1052,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/api.ts#L1016-L1052","documentation":"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.","triggerScenarios":"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).","commonSituations":"Passing a UI-specific operator name ('equals', '~', 'between'), forgetting that 'isbetween' is one word, or programmatically building the fields object with an undefined amountOp.","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."],"exampleFix":"// before\nawait updateSchedule(id, { amountOp: 'between' });\n// after\nawait updateSchedule(id, { amountOp: 'isbetween' });","handlingStrategy":"validation","validationCode":"const OPS = ['is', 'isapprox', 'isbetween'];\nif (!OPS.includes(op)) throw new Error(`amountOp must be one of ${OPS.join(', ')}`);\nawait updateSchedule(id, { amountOp: op });","typeGuard":"function isAmountOp(v) {\n  return v === 'is' || v === 'isapprox' || v === 'isbetween';\n}","tryCatchPattern":"try {\n  await actual.updateSchedule(id, { amountOp: op });\n} catch (e) {\n  if (String(e.message).startsWith('Invalid amount operator')) {\n    console.error('Bad operator:', op);\n  } else throw e;\n}","preventionTips":["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"],"tags":["validation","api","schedules"],"backgroundTag":"invalid-enum-value","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}