actualbudget/actual · error

Unknown item type:

Error message

Unknown item type: 

What it means

BudgetCategories' item renderer switches on a discriminated union of budget item types; the default branch is unreachable for well-typed input (hence `item.type` is `never` and the @ts-expect-error). Throwing here guards against data that violates the union at runtime, e.g. a type string produced outside the known set.

Source

Thrown at packages/desktop-client/src/components/budget/BudgetCategories.tsx:376

              content = (
                <IncomeCategory
                  cat={item.value}
                  editingCell={editingCell}
                  isLast={idx === items.length - 1}
                  onEditName={onEditName}
                  onEditMonth={onEditMonth}
                  onSave={_onSaveCategory}
                  onDelete={onDeleteCategory}
                  onDragChange={onDragChange}
                  onReorder={onReorderCategory}
                  onBudgetAction={onBudgetAction}
                  onShowActivity={onShowActivity}
                />
              );
              break;
            default:
              // @ts-expect-error Error is expected here because "item.type" is "never"
              throw new Error('Unknown item type: ' + item.type);
          }

          const pos =
            idx === 0 ? 'first' : idx === items.length - 1 ? 'last' : null;

          return (
            <DropHighlightPosContext.Provider
              key={
                'value' in item
                  ? item.value.id
                  : item.type === 'income-separator'
                    ? 'separator'
                    : idx
              }
              value={pos}
            >
              <View
                style={

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Add a case for the unexpected item.type to the switch so the union is fully handled (TypeScript exhaustiveness will then flag future additions).
  2. Render a neutral fallback (e.g. return null or a placeholder row) in the default branch instead of crashing the whole budget view.
  3. Log the offending type (via logger) before handling, to diagnose where the unknown row originates.

Example fix

// before
default:
  // @ts-expect-error
  throw new Error('Unknown item type: ' + item.type);

// after
default:
  console.warn('Unknown budget item type:', item.type);
  return null;
Defensive patterns

Strategy: type-guard

Validate before calling

const KNOWN_TYPES = ['income', 'total-spend', 'total-income', 'total-leftover'] as const;
type KnownType = typeof KNOWN_TYPES[number];
if (!KNOWN_TYPES.includes(item.type as KnownType)) return null; // skip unknown rows

Type guard

function isKnownBudgetItem(item: BudgetItem): item is BudgetItem & { type: KnownType } {
  return (KNOWN_TYPES as readonly string[]).includes(item.type);
}

Try / catch

try {
  rows.push(renderItem(item));
} catch (e) {
  if (String(e.message).startsWith('Unknown item type')) {
    logger.warn('skipping unknown budget item', item);
    return null;
  } else throw e;
}

Prevention

When it happens

Trigger: Rendering a budget row whose item.type is not one of the handled kinds (e.g. 'income', 'total-spend', etc.) — typically after a new item type is added to the data layer without extending this switch, or corrupted/generated rows carrying an unexpected type.

Common situations: A contributor adds a new budget summary row type and forgets the BudgetCategories switch; plugin/template code injecting rows with a custom type; version skew between the bundled app and data produced by a newer release.

Related errors


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