mastra-ai/mastra · error · MastraError
SCHEDULES_ID_EXISTS
SCHEDULES_ID_EXISTS
Error message
schedules.create: a schedule with id "${id}" already exists. Use update() to modify it or choose a different id. What it means
create() was called with a caller-supplied id that already exists in the schedules storage. The library treats create as create-only for explicit ids and throws a 409-class error directing you to update() instead.
Source
Thrown at packages/core/src/schedules/schedules.ts:401
target,
cron: input.cron,
timezone: input.timezone,
status: input.status ?? 'active',
nextFireAt,
createdAt: now,
updatedAt: now,
...(input.metadata ? { metadata: input.metadata } : {}),
};
const created = await store.createSchedule(schedule);
return toWorkflowSchedule(created)!;
}
async #assertIdAvailable(store: SchedulesStorage, id: string, callerProvided: boolean): Promise<void> {
if (!callerProvided) return;
const existing = await store.getSchedule(id);
if (existing) {
throw new MastraError({
id: 'SCHEDULES_ID_EXISTS',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
details: { status: 409 },
text: `schedules.create: a schedule with id "${id}" already exists. Use update() to modify it or choose a different id.`,
});
}
}
async get(id: string): Promise<AnySchedule | null> {
const schedule = await this.#load(id);
if (!schedule) return null;
return toScheduleView(schedule);
}
async list(filter?: ListSchedulesFilter): Promise<AnySchedule[]> {
const store = await this.#getStore();
const schedules = await store.listSchedules({View on GitHub (pinned to 75dd419e61)
Solutions
- Call schedules.update(id, patch) instead of create() when the schedule may already exist.
- Check existence first with getSchedule(id) (or a get/list call) and branch between create and update.
- Delete the existing schedule if recreation is intended, or choose a unique id.
Example fix
// before
await schedules.create({ id: 'daily-report', cron: '0 8 * * *' });
// after
const existing = await schedules.get('daily-report');
if (existing) {
await schedules.update('daily-report', { cron: '0 8 * * *' });
} else {
await schedules.create({ id: 'daily-report', cron: '0 8 * * *' });
} Defensive patterns
Strategy: fallback
Validate before calling
const existing = await schedules.get('daily-report');
if (existing) throw new Error('exists — use update()'); Try / catch
try {
await schedules.create({ id, ...config });
} catch (e) {
if (String((e as Error).message).includes('already exists')) {
await schedules.update(id, config);
} else throw e;
} Prevention
- Make seed/bootstrap scripts idempotent with get-then-create-or-update.
- Use upsert-style helpers instead of raw create in deploy pipelines.
- Namespace schedule ids per environment to avoid cross-env collisions.
When it happens
Trigger: Calling schedules.create() (or #createAgentSchedule/#createWorkflowSchedule) with an explicit id for which store.getSchedule(id) already returns a schedule.
Common situations: Re-running bootstrap/seed scripts that create schedules on every startup; deploying two instances that both create the same schedule id; typo where a schedule was created earlier and now is re-created with the same name.
Related errors
- EXPERIMENT_ID_CONFLICT
- Thread with id ${newThreadId} already exists
- MastraFactory: integrations [${channelRegistrations.map(({ i
- Directory ${path.basename(targetPath)} already exists
- Directory already exists and is not empty: ${targetDir}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/138f2b9054e0c358.
Report an issue: GitHub.