actualbudget/actual · error
Schedule ${t.name ?? t.scheduleId} does not exist
Error message
Schedule ${t.name ?? t.scheduleId} does not exist What it means
The category template system resolves 'schedule' templates against the set of schedules that exist in the budget. A template referencing a schedule id or name not found in the budget throws during context initialization.
Source
Thrown at packages/loot-core/src/server/budget/category-template-context.ts:492
) {
if (
templates.filter(t => t.type === 'schedule' || t.type === 'by').length ===
0
) {
return;
}
//check schedule existence (prefer scheduleId, fall back to name)
const activeSchedules = await getActiveSchedules();
const scheduleIds = new Set(activeSchedules.map(s => s.id));
const scheduleNames = new Set(
activeSchedules.map(s => s.name?.trim()).filter(Boolean),
);
templates
.filter(t => t.type === 'schedule')
.forEach(t => {
if (t.scheduleId) {
if (!scheduleIds.has(t.scheduleId)) {
throw new Error(
`Schedule ${t.name ?? t.scheduleId} does not exist`,
);
}
} else if (t.name) {
if (!scheduleNames.has(t.name.trim())) {
throw new Error(`Schedule ${t.name.trim()} does not exist`);
}
} else {
throw new Error('Schedule template has no scheduleId or name');
}
});
//find lowest priority
const lowestPriority = Math.min(
...templates
.filter(t => t.type === 'schedule' || t.type === 'by')
.map(t => t.priority),
);
//warn if priority needs fixedView on GitHub (pinned to d4334cb6e6)
Solutions
- Recreate the missing schedule or update the category template note to reference an existing schedule name/id.
- List existing schedules (q('schedules').select('*')) and match template references against them.
- Use schedule ids instead of names for stability across renames.
Example fix
// before // category note: #template schedule Electric Bill (schedule was deleted) // after // recreate the schedule, or update the note to: // #template schedule Electric Bill 2024 (existing schedule name)
Defensive patterns
Strategy: validation
Validate before calling
const schedules = await q('schedules').select('name').execute();
const names = new Set(schedules.map(s => s.name.trim()));
if (!names.has(templateScheduleName)) throw new Error(`Schedule "${templateScheduleName}" not found in this budget`); Try / catch
try {
await app.runBudgetTemplates();
} catch (e) {
if (e.message.includes('does not exist') && e.message.includes('Schedule')) {
console.error('A category note references a missing schedule:', e.message);
} else throw e;
} Prevention
- When deleting a schedule, search category notes for its references first
- Reference schedules by id rather than name in templates
- Recheck template directives after importing/copying budgets
When it happens
Trigger: A category note contains a directive like '#template schedule <name>' where <name> does not match any schedule (deleted schedule, renamed schedule, or schedule from another budget).
Common situations: Deleting or renaming a schedule after writing template directives in category notes; typos in schedule names; copying budget templates between budgets that have different schedules.
Related errors
- Unknown display type: ${String(displayType)}
- Template cannot be null
- An error occurred while parsing the template
- Unknown template type: ${String(type satisfies undefined)}
- Unknown display type: ${String(visualType satisfies never)}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/bc83064ee26113b3.
Report an issue: GitHub.