actualbudget/actual · error
Unrecognized menu option: ${name}
Error message
Unrecognized menu option: ${name} What it means
CategoryGroupActionMenu maps its menu selection callback through a switch and throws when the selected `name` does not match any known case. This is an internal exhaustiveness guard: the Menu component emitted an option ID the action menu does not handle. It usually means the items list and the switch handler are out of sync.
Source
Thrown at packages/desktop-client/src/components/mobile/budget/CategoryGroupActionMenu.tsx:31
onApplyBudgetTemplatesInGroup: () => void;
};
export function CategoryGroupActionMenu({
onApplyBudgetTemplatesInGroup,
...props
}: CategoryGroupActionMenuProps) {
const { t } = useTranslation();
const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
return (
<Menu
{...props}
onMenuSelect={name => {
switch (name) {
case 'apply-budget-templates-in-group':
onApplyBudgetTemplatesInGroup();
break;
default:
throw new Error(`Unrecognized menu option: ${name}`);
}
}}
items={[
...(isGoalTemplatesEnabled
? [
{
name: 'apply-budget-templates-in-group',
text: t('Overwrite with templates'),
},
]
: []),
]}
/>
);
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Add a switch case for the unrecognized option name in onMenuSelect.
- Verify items[] entries and switch cases are kept in sync (a single source of truth for option IDs helps).
- Rebuild/reload the client so the menu component and handler come from the same version.
- Log the incoming name before the default case during development to catch mismatches early.
Example fix
// before
default:
throw new Error(`Unrecognized menu option: ${name}`);
// after
case 'new-option':
onNewOption();
break;
default: {
const exhaustive: never = name;
throw new Error(`Unrecognized menu option: ${String(exhaustive)}`);
} Defensive patterns
Strategy: validation
Validate before calling
const HANDLED = new Set(['apply-budget-templates-in-group']);
if (!HANDLED.has(name)) {
console.warn(`Ignoring unknown menu option: ${name}`);
return;
} Type guard
type MenuOption = 'apply-budget-templates-in-group';
function isMenuOption(name: string): name is MenuOption {
return name === 'apply-budget-templates-in-group';
} Try / catch
try {
onMenuSelect(name);
} catch (err) {
if (String(err).startsWith('Unrecognized menu option')) {
console.warn(`Unknown menu option: ${name}`);
} else {
throw err;
}
} Prevention
- Derive switch cases and items[] from a single shared option-ID union type.
- Use a `never` exhaustiveness check in the default case.
- Add a case whenever a new menu item is added behind a feature flag.
- Test menu handlers with feature flags both on and off.
When it happens
Trigger: `onMenuSelect` receives a menu option name not present in the switch (currently only 'apply-budget-templates-in-group' is handled) — e.g. after a new item is added to `items` without a matching case, or a stale/foreign option ID is dispatched.
Common situations: A developer adds a new menu item to `items` (or a feature flag reveals an item) but forgets to add the corresponding switch case; plugin or shortcut code dispatching an old option name after a rename.
Related errors
- Unrecognized menu option: ${String(item)}
- Unrecognized menu option: ${name}
- Unrecognized menu item: ${name}
- Unrecognized menu option: ${String(name)}
- Internal error: account with ID ${targetAccountId} not found
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/98217f3517804da4.
Report an issue: GitHub.