actualbudget/actual · error

Expected availableValue to be a number but got

Error message

Expected availableValue to be a number but got 

What it means

ToBudgetAmount displays the 'to budget' figure and applies the same invariant as ToBudget: the sheet value (aliased to availableValue) must be a number or null; anything else throws `Expected availableValue to be a number but got <value>`. An empty suffix indicates the offending value stringified to empty, most commonly undefined.

Source

Thrown at packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetAmount.tsx:49

export function ToBudgetAmount({
  prevMonthName,
  style,
  amountStyle,
  onClick,
  isTotalsListTooltipDisabled = false,
  onContextMenu,
}: ToBudgetAmountProps) {
  const { t } = useTranslation();
  const sheetName = useEnvelopeSheetName(envelopeBudget.toBudget);
  const sheetValue = useEnvelopeSheetValue({
    name: envelopeBudget.toBudget,
    value: 0,
  });
  const format = useFormat();
  const availableValue = sheetValue;
  if (typeof availableValue !== 'number' && availableValue !== null) {
    throw new Error(
      'Expected availableValue to be a number but got ' + availableValue,
    );
  }
  const num = availableValue ?? 0;
  const isNegative = num < 0;
  const isPositive = num > 0;

  return (
    <View style={{ alignItems: 'center', ...style }}>
      <Block>{isNegative ? t('Overbudgeted:') : t('To Budget:')}</Block>
      <View>
        <Tooltip
          content={
            <TotalsList
              prevMonthName={prevMonthName}
              style={{
                padding: 7,
              }}

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Gate rendering on budget sheet initialization so the component never reads a not-yet-bound sheet value
  2. Check that the toBudget sheet value producer returns number | null and not undefined/string
  3. Coerce at the call site with Number.isFinite before the guard
  4. Re-sync or clear the local budget database if the persisted value is corrupt

Example fix

// before
const availableValue = sheetValue;
if (typeof availableValue !== 'number' && availableValue !== null) {
  throw new Error('Expected availableValue to be a number but got ' + availableValue);
}
// after
const availableValue = Number.isFinite(sheetValue) ? sheetValue : null;
const num = availableValue ?? 0;
Defensive patterns

Strategy: type-guard

Validate before calling

const availableValue = Number.isFinite(sheetValue) ? sheetValue : null;
if (availableValue === null) {
  // render loading/zero state instead of proceeding
}

Type guard

function isNumberOrNull(v: unknown): v is number | null {
  return v === null || (typeof v === 'number' && Number.isFinite(v));
}

Try / catch

try {
  return <ToBudgetAmount month={month} />;
} catch (e) {
  if (String(e?.message).includes('Expected availableValue to be a number')) {
    return <Text className="tnum">0</Text>;
  }
  throw e;
}

Prevention

When it happens

Trigger: useEnvelopeSheetValue({ name: envelopeBudget.toBudget, value: 0 }) returns undefined or a non-numeric string — the sheet is not yet initialized for the month, the value factory is missing, or stored sheet data is corrupted.

Common situations: Component mounted before budget data loads; navigating months while the sheet recomputes; custom/older sheet value code returning strings; merge/sync producing an invalid cell value.

Related errors


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