actualbudget/actual · error

Unrecognized menu option: ${name}

Error message

Unrecognized menu option: ${name}

What it means

ToBudgetMenu's onMenuSelect switch handles options like resetting the hold buffer and disabling the auto-buffer; any selected item name without a matching case hits the default branch, which throws `Unrecognized menu option: ${name}`. Like BudgetMonthMenu, it enforces that every entry in the (possibly computed) items list has a handler.

Source

Thrown at packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetMenu.tsx:103

        switch (name) {
          case 'transfer':
            onTransfer?.();
            break;
          case 'cover':
            onCover?.();
            break;
          case 'buffer':
            onHoldBuffer?.();
            onBudgetAction?.(month, 'reset-income-carryover', {});
            break;
          case 'reset-buffer':
            onResetHoldBuffer?.();
            break;
          case 'disable-auto-buffer':
            onBudgetAction?.(month, 'reset-income-carryover', {});
            break;
          default:
            throw new Error(`Unrecognized menu option: ${name}`);
        }
      }}
      items={
        items.length > 0
          ? items
          : [
              {
                name: 'none',
                text: t('No actions available'),
                disabled: true,
              },
            ]
      }
    />
  );
}

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Add the missing `case` to the onMenuSelect switch in ToBudgetMenu.tsx
  2. Align the item's `name` string with an existing case (fix typos/renames)
  3. Log and ignore unknown options in the default branch if dynamic items must be supported

Example fix

// before
default:
  throw new Error(`Unrecognized menu option: ${name}`);
// after
case 'reset-hold-buffer':
  onResetHoldBuffer?.();
  break;
default:
  console.warn(`Unrecognized menu option: ${name}`);
Defensive patterns

Strategy: validation

Validate before calling

const KNOWN_TO_BUDGET_OPTIONS = ['reset-hold-buffer','disable-auto-buffer'];
items.filter(i => !KNOWN_TO_BUDGET_OPTIONS.includes(i.name))
  .forEach(i => console.warn(`Dropping unhandled ToBudgetMenu item: ${i.name}`));

Type guard

type ToBudgetMenuOption = 'reset-hold-buffer' | 'disable-auto-buffer';
function isToBudgetOption(name: string): name is ToBudgetMenuOption {
  return name === 'reset-hold-buffer' || name === 'disable-auto-buffer';
}

Try / catch

onMenuSelect={name => {
  try {
    handleOption(name);
  } catch (e) {
    if (String(e?.message).startsWith('Unrecognized menu option')) return;
    throw e;
  }
}}

Prevention

When it happens

Trigger: A menu item name not among the implemented cases ('reset-hold-buffer', 'disable-auto-buffer', etc.) is selected — a new/renamed item added to `items` (including the conditional `items.length > 0 ? items : [...]` branch) without a switch case, or an externally supplied item.

Common situations: Adding a new ToBudget action and missing the handler; renaming a case but not the item; passing custom items via props with names the switch doesn't know.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/d8b85c2c2804001e. Report an issue: GitHub.