actualbudget/actual · error
Cannot create schedules with the same name
Error message
Cannot create schedules with the same name
What it means
`createSchedule` normalizes the schedule name and checks uniqueness via `checkIfScheduleExists`. If another schedule already uses the same (normalized) name, creation is rejected to keep schedule names unique for user clarity.
Source
Thrown at packages/loot-core/src/server/schedules/app.ts:348
const { date: dateCond } = extractScheduleConds(conditions);
if (dateCond == null) {
throw new Error('A date condition is required to create a schedule');
}
if (dateCond.value == null) {
throw new Error('Date is required');
}
const nextDate = getNextDate(dateCond);
const nextDateRepr = nextDate ? toDateRepr(nextDate) : null;
const scheduleFields = schedule && {
...schedule,
name: normalizeScheduleName(schedule.name),
};
if (scheduleFields) {
if (scheduleFields.name) {
if (await checkIfScheduleExists(scheduleFields.name, scheduleId)) {
throw new Error('Cannot create schedules with the same name');
}
}
}
// Create the rule here based on the info
const ruleId = await insertRule({
stage: null,
conditionsOp: 'and',
conditions,
actions: [{ op: 'link-schedule', value: scheduleId }],
});
const now = Date.now();
await db.insertWithUUID('schedules_next_date', {
schedule_id: scheduleId,
local_next_date: nextDateRepr,
local_next_date_ts: now,
base_next_date: nextDateRepr,View on GitHub (pinned to d4334cb6e6)
Solutions
- Pick a unique name or append a suffix before calling createSchedule
- Check for an existing schedule with the same normalized name first and update it instead
- Call `updateSchedule` rather than `createSchedule` when the schedule already exists
- List schedules (`getRules`/schedule queries) to find the conflicting name
Example fix
// before
await createSchedule({ name: 'Rent', conditions }); // may already exist
// after
const existing = (await aqlQuery(q('schedules').filter({ name: 'rent' }))).data;
if (existing.length === 0) {
await createSchedule({ name: 'Rent', conditions });
} Defensive patterns
Strategy: validation
Validate before calling
const name = schedule.name.trim().toLowerCase();
const dup = (await aqlQuery(q('schedules').filter({ name }))).data;
if (dup.length > 0) {
schedule.name = `${schedule.name} (${new Date().toISOString().slice(0, 10)})`;
}
await createSchedule({ ...schedule, conditions }); Try / catch
try {
await createSchedule({ schedule, conditions });
} catch (e) {
if (e.message === 'Cannot create schedules with the same name') {
await createSchedule({ ...schedule, name: schedule.name + ' (2)' }, { conditions });
} else {
throw e;
}
} Prevention
- Check for an existing schedule with the same normalized name before creating
- Update existing schedules instead of creating duplicates in import/automation flows
- Keep names descriptive and unique (include payee/account in the name)
- Make schedule creation idempotent (lookup-then-create or upsert logic)
When it happens
Trigger: Calling `createSchedule` with `schedule.name` equal (case/whitespace-insensitively after normalization) to an existing schedule's name, when a schedule payload with a name is provided.
Common situations: Automations creating recurring schedules (e.g. 'Rent') that already exist; importing schedules twice; syncing devices that both created the same named schedule.
Related errors
- Cannot update schedules with the same name
- A category with the name "${category.name}" already exists.
- Schedule ${t.name ?? t.scheduleId} does not exist
- Schedule ${t.name.trim()} does not exist
- Schedule template has no scheduleId or name
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/b0dc523b8de6aa0d.
Report an issue: GitHub.