actualbudget/actual · error

Schedule ${t.name.trim()} does not exist

Error message

Schedule ${t.name.trim()} does not exist

What it means

The goal-templates engine validates every schedule template against the schedules that actually exist in the budget. When a template references a schedule by name (or by id) that is not in the budget's schedule list, initialization aborts with this error so templates cannot silently do nothing.

Source

Thrown at packages/loot-core/src/server/budget/category-template-context.ts:498

    }
    //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 fixed
    templates
      .filter(t => t.type === 'schedule' || t.type === 'by')
      .forEach(t => {
        if (t.priority !== lowestPriority) {
          throw new Error(
            `Schedule and By templates must be the same priority level. Fix by setting all Schedule and By templates to priority level ${lowestPriority}`,

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Open the schedule pages and confirm a schedule exists whose exact (trimmed) name matches the name in the template line, then correct the template name or the schedule name
  2. If the schedule was deleted intentionally, remove the `#template schedule ...` line from the category note
  3. Alternatively reference the schedule by its scheduleId instead of name, ensuring that schedule still exists

Example fix

// before
#template schedule Paycheck Bi-Weekly
// after (schedule renamed to "Paycheck")
#template schedule Paycheck
Defensive patterns

Strategy: validation

Validate before calling

const scheduleNames = new Set((await aqlQuery('SELECT * FROM schedules')).map(s => s.name));
const name = 'Paycheck';
if (!scheduleNames.has(name)) throw new Error(`Template references unknown schedule: ${name}`);

Type guard

function hasSchedule(name, scheduleNames) {
  return typeof name === 'string' && scheduleNames.has(name.trim());
}

Try / catch

try {
  await init();
} catch (e) {
  if (/^Schedule .* does not exist$/.test(e.message)) {
    // fix or remove the offending schedule template line, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: A `#template schedule <name>` line (or a template object with type 'schedule'/'by' and a `name` field) is processed during budget initialization (init -> checkByAndScheduleAndSpend) and `scheduleNames.has(t.name.trim())` is false — the schedule was renamed, deleted, or never created, or the template name has inconsistent casing/whitespace not matching any schedule name.

Common situations: User deletes or renames a schedule after adding a schedule template line to a category note; typo in the schedule name in the category template; copying template notes between budgets where the target budget lacks the schedule; restoring an older budget file where schedules were removed.

Related errors


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