actualbudget/actual · error
Expected availableValue to be a number but got
Error message
Expected availableValue to be a number but got
What it means
ToBudget reads the 'to budget' amount from the envelope budget sheet via useEnvelopeSheetValue. The hook may legitimately return a number or null (while loading/invalid), but any other type means the sheet cell held bad data. The component guards this invariant and throws `Expected availableValue to be a number but got <value>`. Note the empty message suffix here means the value stringified to empty (e.g. undefined coerced oddly or empty string).
Source
Thrown at packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudget.tsx:50
}: ToBudgetProps) {
const [menuStep, _setMenuStep] = useState<string>('actions');
const triggerRef = useRef(null);
const format = useFormat();
const ref = useRef<HTMLSpanElement>(null);
const setMenuStep = useCallback(
(menu: string) => {
if (menu) ref.current?.focus();
_setMenuStep(menu);
},
[ref, _setMenuStep],
);
const availableValue = useEnvelopeSheetValue({
name: envelopeBudget.toBudget,
value: 0,
});
if (typeof availableValue !== 'number' && availableValue !== null) {
throw new Error(
'Expected availableValue to be a number but got ' + availableValue,
);
}
const [menuOpen, setMenuOpen] = useState(false);
const [position, setPosition] = useState({ crossOffset: 0, offset: 0 });
const resetPosition = (crossOffset = 0, offset = 0) =>
setPosition({ crossOffset, offset });
const handleContextMenu = (e: MouseEvent) => {
e.preventDefault();
const rect = e.currentTarget.getBoundingClientRect();
setPosition({
crossOffset: e.clientX - rect.left,
offset: e.clientY - rect.bottom,
});
setMenuOpen(true);
};View on GitHub (pinned to d4334cb6e6)
Solutions
- Ensure the component only renders when the envelope sheet for the month is loaded (check isBudgetInitialized/loading state)
- Verify the sheetValue provider for envelopeBudget.toBudget always returns number | null
- Coerce defensively at the hook call site: `Number.isFinite(v) ? v : 0`
- Clear corrupted budget cache / re-sync the budget if stored sheet data is bad
Example fix
// before
const availableValue = useEnvelopeSheetValue({ name: envelopeBudget.toBudget, value: 0 });
// after
const raw = useEnvelopeSheetValue({ name: envelopeBudget.toBudget, value: 0 });
const availableValue = typeof raw === 'number' ? raw : null; Defensive patterns
Strategy: type-guard
Validate before calling
const raw = useEnvelopeSheetValue({ name: envelopeBudget.toBudget, value: 0 });
if (raw !== null && typeof raw !== 'number') {
console.warn('toBudget sheet value invalid, skipping render');
return null;
} Type guard
function isSheetNumber(v: unknown): v is number | null {
return v === null || (typeof v === 'number' && Number.isFinite(v));
} Try / catch
try {
return <ToBudget month={month} />;
} catch (e) {
if (String(e?.message).startsWith('Expected availableValue to be a number')) {
return <div className="tnum">0</div>;
}
throw e;
} Prevention
- Only mount budget summary components after the envelope sheet is initialized/loaded
- Keep sheet value factories returning number | null; never return undefined or strings
- Use Number.isFinite coercion at hook boundaries instead of throwing deep in components
- Add an error boundary around budget summary widgets to degrade gracefully
When it happens
Trigger: useEnvelopeSheetValue for envelopeBudget.toBudget returns a non-numeric, non-null value — typically undefined (hook not yet bound to a sheet / called outside sheet scope), an empty string cell, or a corrupted/unsynced sheet value.
Common situations: Rendering ToBudget before the budget sheet is initialized; month changed while the sheet value factory returns stale data; a bug in a custom sheet value provider returning a string; upgrading loot-core where sheet value typing changed.
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/0a2ac056795fa8cd.
Report an issue: GitHub.