actualbudget/actual · error

Can't convert to integer:

Error message

Can't convert to integer: 

What it means

`integer`-typed fields only accept whole JavaScript numbers. Any other value (float, string, boolean, object) is rejected with 'Can't convert to integer' — the helper casts but does not coerce numeric strings, per the TODO in the source noting these conversions are really casts.

Source

Thrown at packages/loot-core/src/server/aql/schema-helpers.ts:49

      }

      return toDateRepr(value);
    case 'date-month':
      return toDateRepr(value.slice(0, 7));
    case 'date-year':
      return toDateRepr(value.slice(0, 4));
    case 'boolean':
      return value ? 1 : 0;
    case 'id':
      if (typeof value !== 'string' && value !== null) {
        throw new Error('Invalid id, must be string: ' + value);
      }
      return value;
    case 'integer':
      if (typeof value === 'number' && Number.isInteger(value)) {
        return value;
      } else {
        throw new Error("Can't convert to integer: " + JSON.stringify(value));
      }
    case 'json':
      return JSON.stringify(value);
    default:
  }
  return value;
}

export function convertOutputType(value, type) {
  if (value === null) {
    if (type === 'boolean') {
      return false;
    }
    return null;
  }

  switch (type) {
    case 'date':

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Coerce explicitly before querying: `Number(value)` and validate with `Number.isInteger` yourself.
  2. Round/convert money to integer cents first (e.g. `Math.round(amount * 100)`).
  3. Fix the upstream producer so the value is a number, not a numeric string.
  4. If the field should allow fractions or strings, it is typed wrong in the schema — reconsider the column type.

Example fix

// before
q('transactions').insert({ amount: String(cents) }); // '500'
// after
const amount = Number(cents);
if (!Number.isInteger(amount)) throw new Error('bad amount');
q('transactions').insert({ amount });
Defensive patterns

Strategy: validation

Validate before calling

const asInt = (v) => {
  const n = Number(v);
  if (!Number.isInteger(n)) throw new Error(`expected integer, got ${JSON.stringify(v)}`);
  return n;
};

Type guard

const isInteger = (v) => typeof v === 'number' && Number.isInteger(v);

Try / catch

try {
  return await runQuery(q.filter({ amount }));
} catch (e) {
  if (e.message.startsWith("Can't convert to integer:")) {
    logger.error('Non-integer value for integer field', { amount });
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a string like '5' from form/URL input, a float like 12.5, null-like sentinel values, or a parsed amount ('-10.99') into an `integer` field in an aql query.

Common situations: Money amounts from user input arriving as decimal strings/floats and being stored in integer fields that expect cents, sort orders or flags read from JSON as strings, and CSV imports where all cells are strings.

Related errors


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