actualbudget/actual · error
Cannot update schedules with the same name
Error message
Cannot update schedules with the same name
What it means
Like creation, updates enforce schedule name uniqueness. `updateSchedule` normalizes the new name and, if a different schedule already uses it (excluding the schedule being updated via the id argument), throws.
Source
Thrown at packages/loot-core/src/server/schedules/app.ts:400
schedule,
conditions,
resetNextDate,
}: {
schedule: Partial<ScheduleEntity> & Pick<ScheduleEntity, 'id'>;
conditions?: RuleConditionEntity[];
resetNextDate?: boolean;
}) {
if (schedule.rule) {
throw new Error('You cannot change the rule of a schedule');
}
const scheduleFields = { ...schedule };
if ('name' in scheduleFields) {
scheduleFields.name = normalizeScheduleName(scheduleFields.name);
if (
scheduleFields.name &&
(await checkIfScheduleExists(scheduleFields.name, scheduleFields.id))
) {
throw new Error('Cannot update schedules with the same name');
}
}
let rule;
// This must be outside the `batchMessages` call because we change
// and then read data
if (conditions) {
const { date: dateCond } = extractScheduleConds(conditions);
if (dateCond && dateCond.value == null) {
throw new Error('Date is required');
}
// We need to get the full rule to merge in the updated
// conditions
rule = await getRuleForSchedule(schedule.id);
if (rule == null) {
// In the edge case that a rule gets corrupted (either by a bug inView on GitHub (pinned to d4334cb6e6)
Solutions
- Choose a unique name before updating
- Query existing schedule names first and pick a non-conflicting one
- Normalize the name the same way (trim/lowercase) when doing your own uniqueness check
Example fix
// before
await updateSchedule({ schedule: { id: 's1', name: 'Utilities' } }); // s2 already 'Utilities'
// after
await updateSchedule({ schedule: { id: 's1', name: 'Utilities (Studio)' } }); Defensive patterns
Strategy: validation
Validate before calling
const newName = name.trim().toLowerCase();
const taken = (await aqlQuery(q('schedules').filter({ name: newName }))).data;
if (taken.some(s => s.id !== id)) {
throw new Error('Name already used by another schedule');
}
await updateSchedule({ schedule: { id, name } }); Try / catch
try {
await updateSchedule({ schedule: { id, name } });
} catch (e) {
if (e.message === 'Cannot update schedules with the same name') {
logger.warn('Name conflict on update; choosing unique name');
await updateSchedule({ schedule: { id, name: name + ' (copy)' } });
} else {
throw e;
}
} Prevention
- Check name uniqueness (excluding the target schedule's own id) before renaming
- Normalize names (trim/case) the same way the server does in client-side checks
- Guard bulk rename operations against collisions
- Show friendly uniqueness errors in custom UIs before hitting the API
When it happens
Trigger: Calling `updateSchedule({ schedule: { id, name: 'Rent' } })` when another schedule (different id) already has the normalized name 'Rent'.
Common situations: Renaming a schedule to a name taken by another schedule; bulk rename scripts; sync merges assigning duplicate names.
Related errors
- Cannot create 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/844b021851f01f2f.
Report an issue: GitHub.