{"record":{"id":"35b9b960e5bfd5ad","repo":"actualbudget/actual","slug":"unrecognized-menu-item-name-35b9b9","errorCode":null,"errorMessage":"Unrecognized menu item: ${name}","messagePattern":"Unrecognized menu item: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/components/budget/tracking/BudgetMenu.tsx","lineNumber":48,"sourceCode":"        onCopyLastMonthAverage?.();\n        break;\n      case 'set-single-3-avg':\n        onSetMonthsAverage?.(3);\n        break;\n      case 'set-single-6-avg':\n        onSetMonthsAverage?.(6);\n        break;\n      case 'set-single-12-avg':\n        onSetMonthsAverage?.(12);\n        break;\n      case 'apply-single-category-template':\n        onApplyBudgetTemplate?.();\n        break;\n      case 'copy-until-year-end':\n        onCopyUntilYearEnd?.();\n        break;\n      default:\n        throw new Error(`Unrecognized menu item: ${name}`);\n    }\n  };\n\n  return (\n    <Menu\n      {...props}\n      onMenuSelect={onMenuSelect}\n      items={[\n        {\n          name: 'copy-single-last',\n          text: t(\"Copy last month's budget\"),\n        },\n        {\n          name: 'set-single-3-avg',\n          text: t('Set to 3 month average'),\n        },\n        {\n          name: 'set-single-6-avg',","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/budget/tracking/BudgetMenu.tsx#L30-L66","documentation":"BudgetMenu's onMenuSelect handler maps menu item names to callback props via a switch statement; any name not in the known cases hits the default branch which throws. This is an internal invariant check: the Menu component invokes onMenuSelect(name) with the `name` field of the clicked item, so it should never fire unless the items list and switch are out of sync (or a custom item is spread into the Menu via {...props}).","triggerScenarios":"Rendering a Menu (spread through {...props}) that contains an item whose `name` is not one of: copy-single-last, set-single-3-avg, set-single-6-avg, set-single-12-avg, apply-single-category-template, copy-until-year-end, and then clicking it.","commonSituations":"A fork or plugin adds a custom menu item to BudgetMenu without adding a matching case; an upstream rename of an item name (e.g. 'copy-last-month' vs 'copy-single-last') leaves a stale consumer; refactoring the switch but forgetting the conditional goal-templates item.","solutions":["Add a `case` for the unknown item name in onMenuSelect (packages/desktop-client/src/components/budget/tracking/BudgetMenu.tsx:28) wired to the right callback.","Remove or rename the offending menu item in the `items` array so its `name` matches an existing case.","As a softer fix, replace the throw in the default branch with a console/logger warning so a stray item doesn't crash the budget page."],"exampleFix":"// before\ncase 'copy-until-year-end':\n  onCopyUntilYearEnd?.();\n  break;\ndefault:\n  throw new Error(`Unrecognized menu item: ${name}`);\n\n// after\ncase 'copy-until-year-end':\n  onCopyUntilYearEnd?.();\n  break;\ncase 'my-new-item':\n  onMyNewItem?.();\n  break;\ndefault:\n  console.warn(`Unrecognized menu item: ${name}`);","handlingStrategy":"validation","validationCode":"const KNOWN_ITEMS = ['copy-single-last','set-single-3-avg','set-single-6-avg','set-single-12-avg','apply-single-category-template','copy-until-year-end'];\nconst isKnownItem = (name: string): boolean => KNOWN_ITEMS.includes(name);\n// validate menu items before rendering:\nconst safeItems = items.filter(item => isKnownItem(item.name));","typeGuard":"function isBudgetMenuItem(name: string): name is 'copy-single-last' | 'set-single-3-avg' | 'set-single-6-avg' | 'set-single-12-avg' | 'apply-single-category-template' | 'copy-until-year-end' {\n  return ['copy-single-last','set-single-3-avg','set-single-6-avg','set-single-12-avg','apply-single-category-template','copy-until-year-end'].includes(name);\n}","tryCatchPattern":"try {\n  onMenuSelect(name);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Unrecognized menu item')) {\n    logger.warn(`Ignoring unknown menu item: ${name}`);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Type menu item names as a string-literal union shared by the items array and the switch.","Drive the switch from a Record<ItemName, () => void> map so missing handlers are compile errors.","Never inject extra items into BudgetMenu via prop spread without extending the component."],"tags":["react","menu","unhandled-switch-case","ui-crash"],"backgroundTag":"unrecognized-enum-value","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}