actualbudget/actual · error

Invalid recurring date config

Error message

Invalid recurring date config

What it means

recurConfigToRSchedule converts a schedule's recurring-date configuration into an RSchedule rule. The config's frequency field must be one of the supported values (daily, weekly, monthly, yearly); anything else falls to the default branch and throws this generic Error.

Source

Thrown at packages/loot-core/src/shared/schedules.ts:251

      if (config.patterns && config.patterns.length > 0) {
        const days = config.patterns.filter(p => p.type === 'day');
        const dayNames = config.patterns.filter(p => p.type !== 'day');

        return [
          days.length > 0 && { ...base, byDayOfMonth: days.map(p => p.value) },
          dayNames.length > 0 && {
            ...base,
            byDayOfWeek: dayNames.map(p => [abbrevDay(p.type), p.value]),
          },
        ].filter(Boolean);
      } else {
        // Nothing to do
        return [base];
      }
    case 'yearly':
      return [base];
    default:
      throw new Error('Invalid recurring date config');
  }
}

export function extractScheduleConds(conditions) {
  return {
    payee:
      conditions.find(cond => cond.op === 'is' && cond.field === 'payee') ||
      conditions.find(
        cond => cond.op === 'is' && cond.field === 'description',
      ) ||
      null,
    account:
      conditions.find(cond => cond.op === 'is' && cond.field === 'account') ||
      conditions.find(cond => cond.op === 'is' && cond.field === 'acct') ||
      null,
    amount:
      conditions.find(
        cond =>

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Inspect the schedule's conditions in the DB/rules and correct the frequency to one of daily|weekly|monthly|yearly
  2. Delete and recreate the broken schedule from the UI
  3. Validate the recurring config before persisting it (reject unknown frequencies at input time)
  4. Check for version mismatch between the tool that created the schedule and the current app version

Example fix

// before
{ frequency: 'biweekly', start: '2024-01-01' }
// after
{ frequency: 'weekly', interval: 2, start: '2024-01-01' }
Defensive patterns

Strategy: validation

Validate before calling

const VALID = ['daily','weekly','monthly','yearly'];
function isValidRecurConfig(cfg) {
  return cfg && typeof cfg.frequency === 'string' && VALID.includes(cfg.frequency);
}
if (!isValidRecurConfig(cond.value)) throw new Error('Bad frequency before saving schedule');

Type guard

const VALID = ['daily','weekly','monthly','yearly'] as const;
type Frequency = typeof VALID[number];
function isFrequency(f: unknown): f is Frequency {
  return typeof f === 'string' && (VALID as readonly string[]).includes(f);
}

Try / catch

try {
  const rdates = recurConfigToRSchedule(cond.value);
} catch (e) {
  if (e.message === 'Invalid recurring date config') {
    logger.log('Skipping schedule with unsupported frequency', cond.value);
    rdates = null; // degrade gracefully
  } else throw e;
}

Prevention

When it happens

Trigger: Reading a schedule whose recurring_date/condition object has a frequency value outside the supported set — e.g. corrupted schedule data, a schedule serialized by a newer/older version, or hand-edited rule JSON passed into rules/schedule APIs.

Common situations: Restoring budgets from other tools or manual DB edits that wrote an unsupported frequency; version drift where an old client saved a frequency the current code no longer maps; programming errors building a schedule config programmatically.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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