actualbudget/actual · error
No rule found for schedule
Error message
No rule found for schedule
What it means
`setNextDate` looks up the schedule's rule only when `conditions` were not supplied; if the resulting rule is null (rule id points to a deleted/missing rule) it throws 'No rule found for schedule'. This guards against computing the next date from nonexistent conditions.
Source
Thrown at packages/loot-core/src/server/schedules/app.ts:227
}
export async function setNextDate({
id,
start,
conditions,
reset,
skipRequested,
}: {
id: string;
start?;
conditions?;
reset?: boolean;
skipRequested?: boolean;
}) {
if (conditions == null) {
const rule = await getRuleForSchedule(id);
if (rule == null) {
throw new Error('No rule found for schedule');
}
conditions = rule.serialize().conditions;
}
const { date: dateCond } = extractScheduleConds(conditions);
let { data: nextDate } = await aqlQuery(
q('schedules').filter({ id }).calculate('next_date'),
);
if (skipRequested === true) {
const skipWeekend: boolean = dateCond.value?.skipWeekend;
const weekendSolveMode: string = dateCond.value?.weekendSolveMode;
if (weekendSolveMode === 'before' && skipWeekend === true) {
const parsedNextDate = parseDate(nextDate);
if (d.isFriday(parsedNextDate) || d.isWeekend(parsedNextDate)) {
// nextDate is on weekend or friday, moving to mondayView on GitHub (pinned to d4334cb6e6)
Solutions
- Pass explicit `conditions` containing a valid date condition to `setNextDate` so the rule lookup is skipped
- Check the schedules table `rule` column references an existing rule id
- Recreate the rule for the schedule or delete and recreate the schedule
- Pass `reset: true` with conditions to reinitialize the schedule
Example fix
// before
await setNextDate(scheduleId, { reset: true }); // rule missing -> throws
// after
await setNextDate(scheduleId, {
reset: true,
conditions: [
{ field: 'date', op: 'isapprox', value: { frequency: 'monthly', start: '2026-01-01' } },
],
}); Defensive patterns
Strategy: validation
Validate before calling
const ruleId = (await aqlQuery(q('schedules').filter({ id }).calculate('rule'))).data;
if (!conditions && ruleId == null) {
throw new Error('Cannot setNextDate: schedule has no rule; supply conditions explicitly');
}
await setNextDate(id, { conditions: dateConditions }); Type guard
function isRuleWithConditions(rule) {
return rule != null &&
Array.isArray(rule.serialize().conditions) &&
rule.serialize().conditions.some(c => c.field === 'date');
} Try / catch
try {
await setNextDate(id, { reset: true });
} catch (e) {
if (e.message === 'No rule found for schedule') {
logger.warn('Orphaned schedule', id, '— recreating rule');
await recreateScheduleRule(id);
} else {
throw e;
}
} Prevention
- Pass explicit conditions when the schedule's rule may be missing
- Verify schedules.rule references an existing rule before schedule maintenance APIs
- Delete schedules together with their rules to avoid orphans
- Run periodic integrity checks for schedules with null or dangling rule ids
When it happens
Trigger: Calling `setNextDate(id, ...)` without `conditions` when the schedule's backing rule no longer exists (deleted rule, stale rule id), via updateSchedule, skipNextDate, or the schedules advancement service.
Common situations: Rules deleted out-of-band while schedules remained; sync conflicts removing the rule but not the schedule; database restored partially.
Related errors
- Transfer payee with account ID ${id} not found.
- Schedule not attached to a rule
- Account with ID ${upgradingId} not found.
- Transfer payee with account ID ${transferAccountId} not foun
- Subtransaction amount is invalid, must be an integer: ${sub.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/fc7cd992ed31d5c2.
Report an issue: GitHub.