{"record":{"id":"c8fddf633c66a1e6","repo":"actualbudget/actual","slug":"unrecognized-menu-option-string-name-c8fddf","errorCode":null,"errorMessage":"Unrecognized menu option: ${String(name)}","messagePattern":"Unrecognized menu option: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/components/budget/tracking/BalanceMenu.tsx","lineNumber":37,"sourceCode":"export function BalanceMenu({\n  categoryId,\n  onCarryover,\n  ...props\n}: BalanceMenuProps) {\n  const { t } = useTranslation();\n  const carryover = useTrackingSheetValue(\n    trackingBudget.catCarryover(categoryId),\n  );\n  return (\n    <Menu\n      {...props}\n      onMenuSelect={name => {\n        switch (name) {\n          case 'carryover':\n            onCarryover?.(!carryover);\n            break;\n          default:\n            throw new Error(`Unrecognized menu option: ${String(name)}`);\n        }\n      }}\n      items={[\n        {\n          name: 'carryover',\n          text: carryover\n            ? t('Remove overspending rollover')\n            : t('Rollover overspending'),\n        },\n      ]}\n    />\n  );\n}\n","sourceCodeStart":19,"sourceCodeEnd":51,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/budget/tracking/BalanceMenu.tsx#L19-L51","documentation":"BalanceMenu (tracking budget) currently supports exactly one action, 'carryover'; its onMenuSelect switch throws `Unrecognized menu option: ${String(name)}` for any other name. Any item added to the items array without a corresponding case triggers this crash on click.","triggerScenarios":"A BalanceMenu item whose name is not 'carryover' is selected — typically after adding a new menu item (e.g. a transfer or hold action from the envelope variant) without extending the switch, or passing items with mismatched names.","commonSituations":"Porting menu items from the envelope BudgetMenu variant to the tracking BalanceMenu without porting handlers; renames/typos in the item name; plugin-injected menu entries.","solutions":["Add a `case` for the new option name in BalanceMenu's onMenuSelect switch","Ensure the item's `name` is exactly 'carryover' (or whatever handlers exist)","Replace the throw with a warning default if the menu is expected to grow dynamically"],"exampleFix":"// before\ndefault:\n  throw new Error(`Unrecognized menu option: ${String(name)}`);\n// after\ncase 'transfer-to-sinking':\n  onTransfer?.();\n  break;\ndefault:\n  throw new Error(`Unrecognized menu option: ${String(name)}`);","handlingStrategy":"validation","validationCode":"if (name !== 'carryover') {\n  console.warn(`BalanceMenu ignoring unsupported option: ${String(name)}`);\n  return;\n}","typeGuard":"type BalanceMenuOption = 'carryover';\nfunction isBalanceMenuOption(name: string): name is BalanceMenuOption {\n  return name === 'carryover';\n}","tryCatchPattern":"try {\n  handleBalanceAction(name);\n} catch (e) {\n  if (String(e?.message).startsWith('Unrecognized menu option')) {\n    logger.warn('unknown balance menu option ignored');\n    return;\n  }\n  throw e;\n}","preventionTips":["Type the items array with a name union matching the switch so adding an item without a handler fails typecheck","When porting items from the envelope menu variant, port the handlers at the same time","Add an exhaustiveness assertion in the default branch during development","Add a test that clicks every rendered menu item to assert no case is missing"],"tags":["switch-default","unhandled-menu-item","react","budget-ui"],"backgroundTag":"unrecognized-enum-value","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}