actualbudget/actual · error

Target month has passed, remove or update the target month

Error message

Target month has passed, remove or update the target month

What it means

A `by` template targets a month that is already in the past, and the template is not repeating. The engine throws because the target can never be reached and the template would have no effect.

Source

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

      .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;
        }
      });
    // check if the target date is past and not repeating
    templates
      .filter(t => t.type === 'by' || t.type === 'spend')
      .forEach(t => {
        const range = monthUtils.differenceInCalendarMonths(
          `${t.month}`,
          month,
        );
        if (range < 0 && !(t.repeat || t.annual)) {
          throw new Error(
            `Target month has passed, remove or update the target month`,
          );
        }
      });
  }

  static async checkPercentage(templates: Template[]) {
    const pt = templates.filter(t => t.type === 'percentage');
    if (pt.length === 0) return;

    const availCategories = await db.getCategories();
    const incomeCategories = availCategories.filter(c => c.is_income);
    const availNames = new Set(
      incomeCategories.map(c => c.name.toLocaleLowerCase()),
    );
    const availIds = new Set(incomeCategories.map(c => c.id));

    const specialSources = new Set(['all income', 'available funds']);

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Update the target month in the template to a current or future month
  2. Add `repeat each` or make it an `annual` template if the goal should recur
  3. Remove the outdated `#template by ...` line if the goal is complete

Example fix

// before
#template by 2024-06
// after
#template by 2027-01
Defensive patterns

Strategy: validation

Validate before calling

const target = '2024-06';
const diff = monthUtils.differenceInCalendarMonths(target, monthUtils.currentMonth());
if (diff < 0) throw new Error(`by-target ${target} is in the past; add repeat/annual or update the month`);

Type guard

function isReachingableTarget(t, month) {
  return monthUtils.differenceInCalendarMonths(String(t.month), month) >= 0 || Boolean(t.repeat) || Boolean(t.annual);
}

Try / catch

try {
  await init();
} catch (e) {
  if (e.message.includes('Target month has passed')) {
    // update the by-month, add repeat/annual, or delete the line
  } else throw e;
}

Prevention

When it happens

Trigger: `checkByAndScheduleAndSpend` (init) computes `differenceInCalendarMonths(t.month, currentMonth) < 0` for a template where neither `repeat` nor `annual` is set — e.g. `#template by 2024-06` evaluated in a later month.

Common situations: Leaving an old one-time savings-goal template in place after its target date passed; template notes copied from an old budget; annual goals mistakenly written without the `annual`/`repeat` keyword.

Related errors


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