{"record":{"id":"65529c7d6a70bdc1","repo":"actualbudget/actual","slug":"unknown-budget-action-type-string-type","errorCode":null,"errorMessage":"Unknown budget action type: ${String(type)}","messagePattern":"Unknown budget action type: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/budget/mutations.ts","lineNumber":896,"sourceCode":"            month,\n            N: 12,\n            category: args.category,\n          });\n          return null;\n        case 'copy-single-last':\n          await send('budget/copy-single-month', {\n            month,\n            category: args.category,\n          });\n          return null;\n        case 'copy-until-year-end':\n          await send('budget/copy-until-year-end', {\n            month,\n            category: args.category,\n          });\n          return null;\n        default:\n          throw new Error(`Unknown budget action type: ${String(type)}`);\n      }\n    },\n    onSuccess: notification => {\n      if (notification) {\n        dispatch(\n          addNotification({\n            notification: translateBudgetTemplateNotification(notification, t),\n          }),\n        );\n      }\n    },\n    onError: error => {\n      console.error('Error applying budget action:', error);\n      dispatchErrorNotification(\n        dispatch,\n        t('There was an error applying the budget action. Please try again.'),\n        error,\n      );","sourceCodeStart":878,"sourceCodeEnd":914,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/budget/mutations.ts#L878-L914","documentation":"useBudgetActions' mutation builds a server call via a switch over the budget action type; the default branch throws for any type string not in the known union. It is a developer-facing exhaustiveness error: an action type reached the hook that the switch does not handle. The mutation's onError handler then surfaces a generic notification to the user.","triggerScenarios":"Calling applyBudgetAction.mutate({ type: 'some-new-action', ... }) (or dispatching a budget action through a menu/component) with a type string that is not one of the handled cases, e.g. a typo, a removed/renamed action, or a new action added to the type union without adding a switch case.","commonSituations":"Adding a new budget action type to the union but forgetting the switch case; typos in template/action strings from budget templates ('copy-single-last' vs 'copy-last'); stale code after refactoring action names.","solutions":["Use one of the supported action types handled by the switch (e.g. 'carryover', 'copy-single-last', 'set-single-3-avg')","Fix the typo in the action type string at the call site","If a new action was added, add a case to the switch in useBudgetActions (packages/desktop-client/src/budget/mutations.ts) mapping it to the right 'budget/*' server call","Check the type union definition for budget actions and ensure switch exhaustiveness (a never check in default) so this fails at compile time"],"exampleFix":"// before\ndefault:\n  throw new Error(`Unknown budget action type: ${String(type)}`);\n// after\ndefault: {\n  const _exhaustive: never = type;\n  throw new Error(`Unknown budget action type: ${String(_exhaustive)}`);\n}","handlingStrategy":"type-guard","validationCode":"const KNOWN_ACTIONS = ['apply-multiple-templates','carryover','copy-single-last','copy-until-year-end','reset-income-carryover','set-single-3-avg','set-single-6-avg','set-single-12-avg'] as const;\nif (!KNOWN_ACTIONS.includes(type)) {\n  throw new Error(`Unsupported budget action: ${type}`);\n}","typeGuard":"type BudgetActionType = typeof KNOWN_ACTIONS[number];\nfunction isBudgetActionType(t: string): t is BudgetActionType {\n  return (KNOWN_ACTIONS as readonly string[]).includes(t);\n}","tryCatchPattern":"try {\n  await applyBudgetAction.mutateAsync({ type, month, args });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Unknown budget action type')) {\n    dispatch(addNotification({ notification: { type: 'error', message: 'Unsupported budget action' } }));\n  } else throw e;\n}","preventionTips":["Keep the action type union and the switch in sync with a never-exhaustiveness check in default","Centralize the list of valid action types in one exported const","Validate action strings from budget templates against the union before dispatching","Add unit tests covering every action type in the union"],"tags":["react","budget","switch-exhaustiveness","developer-error"],"backgroundTag":"unknown-enum-value","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}