actualbudget/actual · error
Unrecognized menu option: ${String(item)}
Error message
Unrecognized menu option: ${String(item)} What it means
HelpMenu's handleItemSelect switches over the selected menu item's name and dispatches the corresponding action (open URL, start tour, push modal, etc.). Any item name that reaches the default branch is not one of the known options, so the component throws 'Unrecognized menu option' to surface the programming mistake loudly rather than silently doing nothing.
Source
Thrown at packages/desktop-client/src/components/HelpMenu.tsx:106
const handleItemSelect = (item: HelpMenuItem) => {
switch (item) {
case 'docs':
openDocsForCurrentPage();
break;
case 'discord':
window.Actual.openURLInBrowser('https://discord.gg/pRYNYr4W5A');
break;
case 'keyboard-shortcuts':
dispatch(pushModal({ modal: { name: 'keyboard-shortcuts' } }));
break;
case 'start-tour':
startTour();
break;
case 'goal-templates':
dispatch(pushModal({ modal: { name: 'goal-templates' } }));
break;
default:
throw new Error(`Unrecognized menu option: ${String(item)}`);
}
};
useHotkeys('?', () => setMenuOpen(true), { useKey: true });
return (
<SpaceBetween>
<HelpButton ref={menuButtonRef} onPress={toggleMenuOpen} />
<Popover
placement="bottom end"
offset={8}
triggerRef={menuButtonRef}
isOpen={isMenuOpen}
onOpenChange={() => setMenuOpen(false)}
>
<Menu
onMenuSelect={(item: HelpMenuItem) => {View on GitHub (pinned to d4334cb6e6)
Solutions
- Add a `case` for the new item name in handleItemSelect before dispatching.
- Check for typos and keep item names in the items array in sync with the switch cases.
- Type the menu item names as a union so TypeScript flags unhandled names at compile time.
- Rebuild/reload the client if a stale bundle is serving an outdated menu.
- If you only meant to trigger the help menu, use the '?' hotkey or a known item name (e.g. 'goal-templates').
Example fix
// before
case 'goal-templates':
dispatch(pushModal({ modal: { name: 'goal-templates' } }));
break;
default:
throw new Error(`Unrecognized menu option: ${String(item)}`);
// after
case 'my-new-item':
dispatch(openMyNewItem());
break;
case 'goal-templates':
dispatch(pushModal({ modal: { name: 'goal-templates' } }));
break; Defensive patterns
Strategy: type-guard
Validate before calling
type HelpMenuItem = 'settings-file' | 'goal-templates' | 'start-tour';
const knownItems: readonly HelpMenuItem[] = ['settings-file', 'goal-templates', 'start-tour'];
function isKnownHelpItem(item) {
return knownItems.includes(item);
}
if (!isKnownHelpItem(item)) return; // skip dispatch Type guard
function isHelpMenuItem(value) {
return typeof value === 'string' && ['settings-file','goal-templates','start-tour'].includes(value);
} Try / catch
try {
handleItemSelect(item);
} catch (e) {
if (e.message.startsWith('Unrecognized menu option')) {
logger.warn('Ignoring unknown help menu item', item);
return;
}
throw e;
} Prevention
- Type menu item names as a string union shared between the items list and the switch.
- Exhaustive-switch with a `satisfies never` check so new items force a case update.
- Keep item definitions and handleItemSelect cases in the same file/adjacent code.
- Test the HelpMenu click path for every defined item.
When it happens
Trigger: Adding a new item to the HelpMenu's items list (or onSelect invocation) without adding a matching case in handleItemSelect; passing an item with a changed or renamed name; a typo in the item name; a stale cached item from a plugin/extension of the menu.
Common situations: Contributing a new help menu entry and forgetting the switch case; renaming an existing item in one place only; a stale client bundle serving an outdated menu.
Related errors
- Unknown modal
- Unrecognized menu option: ${String(name)}
- Unrecognized menu item: ${name}
- Unrecognized menu option: ${String(name)}
- Unknown budget action type: ${String(type)}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/3e05304ef3fbaeca.
Report an issue: GitHub.