actualbudget/actual · error
Unrecognized menu option: ${name}
Error message
Unrecognized menu option: ${name} What it means
BudgetMonthMenu renders a dropdown of budget actions (copy last month, set to zero, apply templates, etc.). Its onMenuSelect handler is a switch over the selected item's `name`; if the selected name has no case, the default branch throws `Unrecognized menu option: ${name}`. This is an internal consistency guard: the items array and the switch must stay in sync, and this crash signals they did not.
Source
Thrown at packages/desktop-client/src/components/budget/envelope/budgetsummary/BudgetMonthMenu.tsx:67
onSetMonthsAverage(6);
break;
case 'set-12-avg':
onSetMonthsAverage(12);
break;
case 'check-templates':
onCheckTemplates();
break;
case 'apply-goal-template':
onApplyBudgetTemplates();
break;
case 'overwrite-goal-template':
onOverwriteWithBudgetTemplates();
break;
case 'cleanup-goal-template':
onEndOfMonthCleanup();
break;
default:
throw new Error(`Unrecognized menu option: ${name}`);
}
}}
items={[
{ name: 'copy-last', text: t("Copy last month's budget") },
{ name: 'set-zero', text: t('Set budgets to zero') },
{
name: 'set-3-avg',
text: t('Set budgets to 3 month average'),
},
{
name: 'set-6-avg',
text: t('Set budgets to 6 month average'),
},
{
name: 'set-12-avg',
text: t('Set budgets to 12 month average'),
},
...(isGoalTemplatesEnabledView on GitHub (pinned to d4334cb6e6)
Solutions
- Add a `case` for the missing option name in the onMenuSelect switch in BudgetMonthMenu.tsx
- Fix the typo/wrong name in the menu item so it matches an existing case exactly
- Make the default branch a console warning (or no-op) instead of a throw if extensibility is intended
Example fix
// before
default:
throw new Error(`Unrecognized menu option: ${name}`);
// after
case 'apply-budget-template':
onApplyBudgetTemplates();
break;
default:
throw new Error(`Unrecognized menu option: ${name}`); Defensive patterns
Strategy: validation
Validate before calling
const KNOWN = ['copy-last','set-zero','check-templates','overwrite-with-templates','cleanup-goal-template'];
if (!KNOWN.includes(item.name)) {
console.warn(`Skipping unknown budget menu option: ${item.name}`);
return;
} Type guard
type BudgetMenuOption = 'copy-last' | 'set-zero' | 'check-templates' | 'overwrite-with-templates' | 'cleanup-goal-template';
function isBudgetMenuOption(name: string): name is BudgetMenuOption {
return ['copy-last','set-zero','check-templates','overwrite-with-templates','cleanup-goal-template'].includes(name);
} Try / catch
try {
renderApp();
} catch (e) {
if (String(e?.message).startsWith('Unrecognized menu option')) {
logger.warn({ name: 'menu-option-fallback' }, 'unknown menu option ignored');
} else throw e;
} Prevention
- Type menu item names as a union type shared by `items` and the switch so TS exhaustiveness checking catches gaps
- Add an exhaustiveness check (`name satisfies never`) in the default branch during development
- When adding a menu item, add the switch case in the same commit/PR
- Write a unit test that dispatches every item name in the items array through onMenuSelect
When it happens
Trigger: A MenuItem whose `name` is not one of 'copy-last', 'set-zero', 'check-templates', 'overwrite-with-templates', 'cleanup-goal-template' is dispatched to onMenuSelect — e.g. a newly added menu item without a matching switch case, a plugin/custom item injected into the items list, or a stale/typo'd name string.
Common situations: Developers adding a new budget action to the `items` array but forgetting to add the corresponding `case` in the switch; rebasing code where a case was renamed in one place but not the other; third-party code overriding the menu items.
Related errors
- Unrecognized menu option: ${name}
- Unrecognized menu option: ${String(name)}
- InitialFocus expects a single valid React element as its chi
- Unknown budget action type: ${String(type)}
- Unknown display type: ${String(type satisfies never)}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/6d02638db9af5d41.
Report an issue: GitHub.