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
- Gate rendering on budget sheet initialization so the component never reads a not-yet-bound sheet value
- Check that the toBudget sheet value producer returns number | null and not undefined/string
- Coerce at the call site with Number.isFinite before the guard
- 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
- Guard against undefined before the invariant check: treat undefined like null (loading state)
- Verify the sheet value binding for envelopeBudget.toBudget exists for the current month
- Normalize all sheet reads through one helper that guarantees number | null
- Cover month-navigation races with tests that mount the component before data loads
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
- Expected availableValue to be a number but got
- InitialFocus expects a single valid React element as its chi
- Unknown budget action type: ${String(type)}
- Unknown display type: ${String(type satisfies never)}
- Unhandled action type: ${action.type}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/663d18bba70f9b0b.
Report an issue: GitHub.