actualbudget/actual · error
Template cannot be null
Error message
Template cannot be null
What it means
getInitialState builds ReducerState from a parsed Template and explicitly rejects null. Callers are expected to pass a template parsed from a category's notes; null means there is nothing to edit, so the function fails fast instead of returning partial state.
Source
Thrown at packages/desktop-client/src/components/budget/goals/reducer.ts:16
import {
addMonths,
dayFromDate,
firstDayOfMonth,
monthFromDate,
} from '@actual-app/core/shared/months';
import type { Template } from '@actual-app/core/types/models/templates';
import type { Action } from './actions';
import type { DisplayTemplateType, ReducerState } from './constants';
export const DEFAULT_PRIORITY = 1;
export const getInitialState = (template: Template | null): ReducerState => {
if (!template) {
throw new Error('Template cannot be null');
}
const type = template.type;
switch (type) {
case 'simple':
return {
template: {
type: 'periodic',
amount: template.monthly ?? 0,
period: {
period: 'month',
amount: 1,
},
starting: firstDayOfMonth(new Date()),
priority: template.priority,
directive: template.directive,
},
displayType: 'fixed',
};View on GitHub (pinned to d4334cb6e6)
Solutions
- Only call getInitialState when a template has been parsed and exists
- Guard the dispatch site: check template != null before dispatching 'set-template'
- Fix the upstream parser so valid template notes produce a Template object, not null
Example fix
// before
dispatch({ type: 'set-template', payload: parsedTemplate });
// after
if (parsedTemplate) {
dispatch({ type: 'set-template', payload: parsedTemplate });
} Defensive patterns
Strategy: validation
Validate before calling
if (template == null) {
return; // or show an empty-editor state instead of dispatching
}
dispatch({ type: 'set-template', payload: template }); Type guard
const hasTemplate = (t: Template | null | undefined): t is Template => t != null && typeof t.type === 'string';
Try / catch
try {
dispatch({ type: 'set-template', payload: template });
} catch (e) {
if (e instanceof Error && e.message === 'Template cannot be null') {
notify('No template found on this category.');
} else throw e;
} Prevention
- Only open the template editor when a parsed template exists
- Check parser output for null before dispatching
- Handle the no-template case in UI state instead of the reducer
When it happens
Trigger: Calling getInitialState(null), which happens when templateReducer receives a 'set-template' action with null payload, or mapTemplateTypesForUpdate builds a merged template that is null/undefined.
Common situations: Opening the template editor for a category with no template without checking first; a parsing step returning null on malformed notes and its result passed straight to the reducer; race where the template is cleared while the editor is initializing.
Related errors
- Unknown display type: ${String(displayType)}
- An error occurred while parsing the template
- Invalid --name: must be a non-empty string.
- No update fields provided. Use --name or --offbudget.
- Invalid cutoff date: expected a valid date (e.g. YYYY-MM-DD)
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/21e5894196cea9e5.
Report an issue: GitHub.