actualbudget/actual · error · RuleError

parse-recur-date

parse-recur-date

Error message

parse-recur-date: ${e.message}

What it means

`parseRecurDate` wraps any exception raised while parsing a recurring-date descriptor into a `RuleError` with code `parse-recur-date`. Recurring schedule date strings (RRULE-like objects) must conform to the expected descriptor shape; invalid frequency, interval, or sub-date values throw here.

Source

Thrown at packages/loot-core/src/server/rules/rule-utils.ts:235

  }
}

export function parseRecurDate(desc) {
  try {
    const rules = recurConfigToRSchedule(desc);

    return {
      type: 'recur',
      schedule: new RSchedule({
        rrules: rules,
        data: {
          skipWeekend: desc.skipWeekend,
          weekendSolve: desc.weekendSolveMode,
        },
      }),
    };
  } catch (e) {
    throw new RuleError('parse-recur-date', e.message);
  }
}

export function parseDateString(str) {
  if (typeof str !== 'string') {
    return null;
  } else if (str.length === 10) {
    // YYYY-MM-DD
    if (!dateFns.isValid(dateFns.parseISO(str))) {
      return null;
    }

    return { type: 'date', date: str };
  } else if (str.length === 7) {
    // YYYY-MM
    if (!dateFns.isValid(dateFns.parseISO(str + '-01'))) {
      return null;
    }

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Inspect `e.message` embedded in the error — it is the underlying parser message
  2. Validate the recurring descriptor: `frequency` in {daily, weekly, monthly, yearly}, positive `interval`, valid `start` date string
  3. Build schedules through the UI or a schedule-creation helper instead of hand-writing descriptors
  4. Fix the offending condition value in the schedule/rule data

Example fix

// before
{ field: 'date', op: 'isapprox', value: { frequency: 'biweekly', start: '2026-01-01' } }
// after
{ field: 'date', op: 'isapprox', value: { frequency: 'weekly', interval: 2, start: '2026-01-01' } }
Defensive patterns

Strategy: validation

Validate before calling

function isValidRecurDescriptor(v) {
  const freqs = ['daily', 'weekly', 'monthly', 'yearly'];
  return (
    v && typeof v === 'object' &&
    freqs.includes(v.frequency) &&
    (v.interval == null || (Number.isInteger(v.interval) && v.interval > 0)) &&
    typeof v.start === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(v.start)
  );
}

Type guard

function isRecurringDateValue(v) {
  return typeof v === 'object' && v !== null &&
    typeof (v).frequency === 'string' &&
    typeof (v).start === 'string';
}

Try / catch

try {
  const next = parseRecurDate(desc);
} catch (e) {
  if (e.type === 'parse-recur-date') {
    logger.error('Bad recurring descriptor', desc, e.message);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Passing a malformed recurring date object to a date condition (e.g. `frequency` misspelled, missing `start`, invalid `interval`, bad nested `between`/`on` descriptors) which the underlying parser throws on.

Common situations: Hand-authoring recurring schedule conditions via the API; importing schedules from another tool; edited budget data where the `date` condition value was mangled.

Related errors


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