actualbudget/actual · warning

Unsupported template type reached migration

Error message

Unsupported template type reached migration

What it means

getDisplayTypeFromTemplate maps stored goal templates to editor display types during migration of templates to budget automations. A template with type 'error' means the goal template parser failed on that directive; these are supposed to be filtered out upstream by hasUnsupportedDirective before migration. This throw surfaces a bug where an error-typed (unparseable) template leaked into the migration path, indicating the upstream filter missed it.

Source

Thrown at packages/desktop-client/src/components/modals/BudgetAutomationsModal/migrateTemplatesToAutomations.ts:41

    case 'simple':
      return 'fixed';
    case 'limit':
      return 'limit';
    case 'refill':
      return 'refill';
    case 'average':
    case 'copy':
      return 'historical';
    case 'by':
    case 'spend':
      return 'by';
    case 'remainder':
      return 'remainder';
    case 'goal':
      return 'goal';
    case 'error':
      // filtered upstream by hasUnsupportedDirective; surface if it ever isn't
      throw new Error(`Unsupported template type reached migration`);
    default: {
      const _exhaustive: never = template;
      void _exhaustive;
      throw new Error(`Unhandled template type`);
    }
  }
}

// Fill in scheduleId from name (or refresh a stale name from scheduleId) so
// the editor and engine consistently see both.
function hydrateScheduleTemplate(
  template: ScheduleTemplate,
  schedules: readonly ScheduleEntity[],
): ScheduleTemplate {
  const schedule = template.scheduleId
    ? schedules.find(s => s.id === template.scheduleId)
    : template.name
      ? schedules.find(s => s.name?.trim() === template.name?.trim())

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Identify the offending template (its category/note text) and inspect why it parsed as type 'error'.
  2. Fix or remove the malformed goal template directive in the category notes before migrating.
  3. Extend hasUnsupportedDirective so error-typed templates are excluded from the migration input.
  4. Update the parser/migration mapping if a previously supported directive now yields an error template after an upgrade.

Example fix

// before
const toMigrate = templates.filter(t => t.directive === 'template');
// after
const toMigrate = templates.filter(
  t => t.directive === 'template' && !hasUnsupportedDirective(t),
);
Defensive patterns

Strategy: validation

Validate before calling

const migratable = templates.filter(
  t => t.directive === 'template' && t.type !== 'error' && hasSupportedType(t),
);
migrateTemplatesToAutomations(migratable, ...);

Type guard

function isMigratableTemplate(t: Template): boolean {
  return t.type !== 'error' && MIGRATION_SUPPORTED_TYPES.has(t.type);
}

Try / catch

try {
  migrateTemplatesToAutomations(templates, schedules);
} catch (err) {
  if (String(err).includes('Unsupported template type reached migration')) {
    notifyUser('Some goal templates could not be migrated and were skipped.');
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Running migrateTemplatesToAutomations on a budget whose template list still contains templates with `type: 'error'` because hasUnsupportedDirective did not exclude them — e.g. a directive that fails parsing into a supported automation, or a change in the parser producing error templates for previously valid directives.

Common situations: Budgets authored with goal templates that no longer parse after an upgrade; edits to template syntax (renamed/removed directive parameters) leaving error placeholders in notes; the upstream filter's predicate diverging from this switch's cases.

Related errors


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