actualbudget/actual · error
Invalid BUDGET_QUERY dimension: ${dimension}
Error message
Invalid BUDGET_QUERY dimension: ${dimension} What it means
fetchBudgetDimensionValueDirect validates the dimension argument of a BUDGET_QUERY against a fixed allowlist (including 'balance_start', 'balance_end', 'goal', etc.) after lowercasing. If the dimension is not in the set, it throws 'Invalid BUDGET_QUERY dimension: <dimension>'. This guards the direct budget fetch path from unknown or misspelled dimensions.
Source
Thrown at packages/desktop-client/src/hooks/useFormulaExecution.ts:646
}
// Helper: Evaluate budget dimension with already-extracted parameters (used by compositional BUDGET_QUERY)
async function fetchBudgetDimensionValueDirect(
dimension: string,
categoryIds: string[],
startMonth: string,
endMonth: string,
): Promise<number> {
const allowed = new Set([
'budgeted',
'spent',
'balance_start',
'balance_end',
'goal',
]);
const dim = dimension.toLowerCase();
if (!allowed.has(dim)) {
throw new Error(`Invalid BUDGET_QUERY dimension: ${dimension}`);
}
const intervals = monthUtils.rangeInclusive(startMonth, endMonth);
// Helper: sum a dimension across all months/categories
const sumDimension = async (fieldPattern: string): Promise<number> => {
let total = 0;
for (const month of intervals) {
const monthData = await getMonthBudgetData(month);
for (const catId of categoryIds) {
total += getMonthDataValue(monthData, fieldPattern, catId) as number;
}
}
return total;
};
if (dim === 'budgeted') {
return integerToAmount(await sumDimension('budget-{catId}'), 2);View on GitHub (pinned to d4334cb6e6)
Solutions
- Check the spelling of the dimension against the supported list: the allowed set includes 'balance_start', 'balance_end', 'goal' (see the allowlist at useFormulaExecution.ts)
- Lowercase/trim the dimension input before calling, since matching is on the lowercased value
- Add the new dimension to the allowed set in fetchBudgetDimensionValueDirect if it is a legitimately supported dimension
- Validate dimension values at the formula parser layer to give earlier feedback
Example fix
// before
await prefetchBudgetQueries({ dimension: 'BALANCED' });
// after
const VALID = ['sumamount', 'budgeted', 'balance', 'balance_start', 'balance_end', 'goal'];
const dim = String(dimension).toLowerCase().trim();
if (!VALID.includes(dim)) {
throw new Error(`Unsupported dimension, use one of: ${VALID.join(', ')}`);
}
await prefetchBudgetQueries({ dimension: dim }); Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = new Set(['sumamount','budgeted','balance','balance_start','balance_end','goal']);
const assertDimension = (d: string) => {
const dim = String(d).toLowerCase().trim();
if (!ALLOWED.has(dim)) throw new Error(`Invalid dimension ${d}; allowed: ${[...ALLOWED].join(', ')}`);
return dim;
}; Try / catch
try {
await prefetchBudgetQueries(args);
} catch (err) {
if (err.message.startsWith('Invalid BUDGET_QUERY dimension')) {
showError('Choose one of the supported budget dimensions');
} else throw err;
} Prevention
- Keep a single exported constant listing valid dimensions and derive UI dropdowns from it
- Always lowercase/trim user input before comparing against the allowlist
- Add unit tests covering each valid dimension and one invalid one
- When adding dimensions, update the allowlist and docs together
When it happens
Trigger: Calling prefetchBudgetQueries (or code that reaches fetchBudgetDimensionValueDirect) with a BUDGET_QUERY whose dimension string is misspelled, uses different casing with unexpected characters, or is a dimension only supported elsewhere but not in this direct path.
Common situations: Typos in a formula like BUDGET_QUERY(..., "balence"); copying a dimension name from another API that uses different naming; newly added dimensions not yet in the allowlist; passing a non-string such as a number.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Cannot transfer between income and expense categories.
- ${message}
- Formula must start with =
- Amount to hold needs to be greater than 0
- Error importing budget: ${result.error}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/345c0f293a64f0be.
Report an issue: GitHub.