{"record":{"id":"7187d0aaeeccfc2d","repo":"actualbudget/actual","slug":"unrecognized-menu-option-string-name-7187d0","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/modals/EnvelopeIncomeBalanceMenuModal.tsx","lineNumber":120,"sourceCode":"                    textAlign: 'center',\n                    ...styles.veryLargeText,\n                  }}\n                />\n              )}\n            </BalanceWithCarryover>\n          </View>\n          <Menu\n            getItemStyle={() => defaultMenuItemStyle}\n            onMenuSelect={name => {\n              switch (name) {\n                case 'carryover':\n                  onCarryover?.(!carryover);\n                  break;\n                case 'view':\n                  onShowActivity?.();\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('Disable auto hold')\n                  : t('Enable auto hold'),\n              },\n              {\n                name: 'view',\n                text: t('View transactions'),\n              },\n            ]}\n          />\n        </>\n      )}\n    </Modal>","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/modals/EnvelopeIncomeBalanceMenuModal.tsx#L102-L138","documentation":"EnvelopeIncomeBalanceMenuModal throws when the category/envelope menu's onSelect receives an option name with no case in its switch. Handled options include carryover and view; anything else is an invariant violation indicating a menu item was rendered without a corresponding handler.","triggerScenarios":"Selecting an item in the envelope/income-balance context menu whose `name` isn't handled — typically after a new item is appended to the modal's `items` array (e.g. 'transfer', 'hide') without adding its case.","commonSituations":"Contributors adding an envelope menu action without extending the switch; renames of an existing item name string; forks injecting extra menu entries.","solutions":["Add a case for the reported name with the appropriate callback call.","Ensure every object in the `items` array has a matching case in the switch (name strings must match exactly).","Swap the throw for console.warn if unknown options should be ignored at runtime.","Derive the union of item names as a type and make the switch exhaustive to catch this at compile time."],"exampleFix":"// before\ncase 'view':\n  onShowActivity?.();\n  break;\ndefault:\n  throw new Error(`Unrecognized menu option: ${String(name)}`);\n// after\ncase 'view':\n  onShowActivity?.();\n  break;\ncase 'transfer':\n  onTransfer?.();\n  break;\ndefault:\n  console.warn('Unrecognized menu option:', name);","handlingStrategy":"type-guard","validationCode":"const HANDLED = new Set(['carryover', 'view']);\nif (!HANDLED.has(name)) {\n  console.warn('Unknown envelope menu option:', name);\n  return;\n}","typeGuard":"type EnvelopeMenuOption = 'carryover' | 'view';\nfunction isEnvelopeMenuOption(name: string): name is EnvelopeMenuOption {\n  return ['carryover', 'view'].includes(name);\n}","tryCatchPattern":"try {\n  onSelect(name);\n} catch (err) {\n  if (String(err).includes('Unrecognized menu option')) {\n    console.warn('Ignoring menu option', name);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Define item names as a literal union shared between the items array and the switch.","Add a unit test asserting every items entry has a switch case.","Replace the throw with a warn-level default branch for runtime resilience."],"tags":["react","menu","switch-statement","developer-error"],"backgroundTag":"unhandled-switch-case","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}