{"record":{"id":"1983943c3915bd6f","repo":"actualbudget/actual","slug":"unrecognized-menu-option-name","errorCode":null,"errorMessage":"Unrecognized menu option: ${name}","messagePattern":"Unrecognized menu option: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx","lineNumber":51,"sourceCode":"  const balance =\n    useEnvelopeSheetValue(envelopeBudget.catBalance(categoryId)) ?? 0;\n\n  return (\n    <Menu\n      {...props}\n      onMenuSelect={name => {\n        switch (name) {\n          case 'transfer':\n            onTransfer?.();\n            break;\n          case 'carryover':\n            onCarryover?.(!carryover);\n            break;\n          case 'cover':\n            onCover?.();\n            break;\n          default:\n            throw new Error(`Unrecognized menu option: ${name}`);\n        }\n      }}\n      items={[\n        ...(balance > 0\n          ? [\n              {\n                name: 'transfer',\n                text: t('Transfer to another category'),\n              },\n            ]\n          : []),\n        ...(balance < 0\n          ? [\n              {\n                name: 'cover',\n                text: t('Cover overspending'),\n              },\n            ]","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/budget/envelope/BalanceMenu.tsx#L33-L69","documentation":"BalanceMenu's onSelect switch handles a fixed set of menu option names (e.g. transfer, cover, carryover) and throws on anything else. It's an exhaustiveness guard: the items array and the switch must stay in sync, and a mismatch is treated as a programming error.","triggerScenarios":"Calling the menu's onSelect with a name that isn't one of the defined items — usually a custom Menu item added by a caller/parent, or a renamed option where the switch wasn't updated.","commonSituations":"A developer adds an item to the items array but forgets the switch case; a plugin/patched build injects extra options; refactoring item names in one place only.","solutions":["Add the missing `case '<name>':` branch to the onSelect switch matching the item you added to the items array.","Type the item name union and annotate onSelect's parameter so TypeScript flags unmatched names at compile time.","If the option is intentionally a no-op for some contexts (e.g. cover without overbudgeted amount), early-return instead of throwing."],"exampleFix":"// before\ncase 'cover':\n  onCover?.();\n  break;\ndefault:\n  throw new Error(`Unrecognized menu option: ${name}`);\n\n// after\ncase 'cover':\n  onCover?.();\n  break;\ncase 'transfer':\n  onTransfer?.();\n  break;\ndefault:\n  console.warn('Unknown balance menu option', name);","handlingStrategy":"type-guard","validationCode":"type BalanceMenuOption = 'transfer' | 'cover' | 'carryover' | 'hold';\nfunction isBalanceMenuOption(name: string): name is BalanceMenuOption {\n  return ['transfer', 'cover', 'carryover', 'hold'].includes(name);\n}\nif (!isBalanceMenuOption(name)) return;","typeGuard":"function isBalanceMenuOption(name: string): name is BalanceMenuOption {\n  return ['transfer', 'cover', 'carryover', 'hold'].includes(name);\n}","tryCatchPattern":"onSelect={name => {\n  try {\n    handleOption(name);\n  } catch (e) {\n    if (String(e.message).startsWith('Unrecognized menu option')) console.warn(name);\n    else throw e;\n  }\n}}","preventionTips":["Keep the items array and the switch cases derived from one shared union type.","Add a case at the same time you add a menu item — never one without the other.","Use a switch with `name satisfies never` exhaustiveness checking so the compiler catches gaps."],"tags":["typescript","exhaustiveness","menu","budget"],"backgroundTag":"unhandled-enum-case","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}