{"record":{"id":"a2aad84495b8c37a","repo":"actualbudget/actual","slug":"amount-is-invalid-must-be-an-integer-trans-amo","errorCode":null,"errorMessage":"Amount is invalid, must be an integer: ${trans.amount}","messagePattern":"Amount is invalid, must be an integer: (.+?)","errorType":"validation","errorClass":"TransactionError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/accounts/sync.ts","lineNumber":460,"sourceCode":"    payeeNameNormalization?: PayeeNameNormalization;\n  } = {},\n) {\n  const payeesToCreate = new Map();\n\n  const normalized = [];\n  for (let trans of transactions) {\n    // Validate the date because we do some stuff with it. The db\n    // layer does better validation, but this will give nicer errors\n    if (trans.date == null) {\n      throw new Error('`date` is required when adding a transaction');\n    }\n\n    // Strip off the irregular properties\n    const { payee_name: originalPayeeName, subtransactions, ...rest } = trans;\n    trans = rest;\n\n    if (trans.amount != null && !Number.isInteger(trans.amount)) {\n      throw new TransactionError(\n        `Amount is invalid, must be an integer: ${trans.amount}`,\n      );\n    }\n\n    if (subtransactions) {\n      for (const sub of subtransactions) {\n        if (sub.amount != null && !Number.isInteger(sub.amount)) {\n          throw new TransactionError(\n            `Subtransaction amount is invalid, must be an integer: ${sub.amount}`,\n          );\n        }\n      }\n    }\n\n    let payee_name = originalPayeeName;\n    if (payee_name) {\n      const trimmed = payee_name.trim();\n      if (trimmed === '') {","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/accounts/sync.ts#L442-L478","documentation":"Transaction amounts in Actual are stored as integer cents, so normalizeTransactions rejects any transaction whose amount is set but not an integer, throwing a TransactionError. This catches floating-point amounts (e.g. -25.99) or string amounts before they can corrupt the ledger. Amounts must be integer cents, not decimal currency units.","triggerScenarios":"Calling importTransactions/addTransactions with amount = -25.99 (decimal dollars), amount = '-25.99' (string), or NaN — anything where Number.isInteger(amount) is false while amount != null. Subtransactions are validated the same way.","commonSituations":"Integrations passing amounts straight from a bank API/CSV in decimal form without converting to cents; float arithmetic residue; JSON/CSV parsers yielding strings for numeric columns.","solutions":["Convert amounts to integer cents before submission: Math.round(amount * 100).","Parse numeric values explicitly (Number(str)) and round to avoid float residue.","Reject non-numeric or decimal amounts at the import-script level with a validation step.","Use integer math in cents throughout rather than float arithmetic on money."],"exampleFix":"// before\n{ date: '2024-05-01', amount: -25.99, payee_name: 'Kroger' }\n// after\n{ date: '2024-05-01', amount: Math.round(-25.99 * 100), payee_name: 'Kroger' } // -2599","handlingStrategy":"validation","validationCode":"for (const t of txs) {\n  if (t.amount != null && !Number.isInteger(t.amount)) {\n    throw new Error(`amount must be integer cents, got: ${t.amount}`);\n  }\n}","typeGuard":"function isCentsAmount(a: unknown): a is number {\n  return typeof a === 'number' && Number.isInteger(a);\n}","tryCatchPattern":"try {\n  await importTransactions(accountId, txs);\n} catch (e) {\n  if (e instanceof TransactionError && e.message.startsWith('Amount is invalid')) {\n    console.error('Convert amounts to integer cents (Math.round(x * 100)) before importing');\n    return;\n  }\n  throw e;\n}","preventionTips":["Always submit amounts in integer cents; convert once at the ingestion boundary.","Use Math.round(amount * 100) and avoid raw float arithmetic on money.","Parse CSV numerics explicitly with Number() and validate before use.","Run a batch-wide pre-flight check for integer amounts before calling the API."],"tags":["validation","transactions","amount","api"],"backgroundTag":"invalid-amount-format","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}