actualbudget/actual · error

Schedule template has no scheduleId or name

Error message

Schedule template has no scheduleId or name

What it means

A schedule template line was found that carries neither a schedule name nor a scheduleId, so the engine cannot resolve it to any schedule. This is thrown as a template-syntax failure during budget initialization.

Source

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

    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}`,
          );
          //t.priority = lowestPriority;
        }

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Add the schedule name (or scheduleId) to the template line, e.g. `#template schedule My Schedule`
  2. Remove the incomplete template line if it is no longer needed

Example fix

// before
#template schedule
// after
#template schedule Rent
Defensive patterns

Strategy: validation

Validate before calling

const line = '#template schedule';
const parts = line.split(/\s+/).slice(2).filter(Boolean);
if (parts.length === 0) throw new Error('schedule template requires a name or scheduleId');

Type guard

function isCompleteScheduleTemplate(t) {
  return typeof t.scheduleId === 'string' && t.scheduleId.length > 0 || typeof t.name === 'string' && t.name.trim().length > 0;
}

Try / catch

try {
  await init();
} catch (e) {
  if (e.message === 'Schedule template has no scheduleId or name') {
    // locate the bare `#template schedule` line and complete or remove it
  } else throw e;
}

Prevention

When it happens

Trigger: `checkByAndScheduleAndSpend` (called from init) encounters a template of type 'schedule'/'by' where `t.name` is empty/undefined and `t.scheduleId` is missing — e.g. `#template schedule` with no argument, or a template parsed with an empty name value.

Common situations: Incomplete template line typed into a category note; a note-editing mishap that deletes the schedule name but leaves the directive; programmatic template generation that omits the name field.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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