mastra-ai/mastra · error · MastraError
SCHEDULES_INVALID_CRON
SCHEDULES_INVALID_CRON
Error message
Schedule${where}: ${error instanceof Error ? error.message : String(error)} What it means
The schedule's 'cron' expression (or its 'timezone') failed validation by validateCron, and the underlying parser message is re-thrown as a MastraError with the SCHEDULES_INVALID_CRON id. Mastra validates the cron and timezone eagerly in assertValidScheduleDefinition so an invalid expression is caught at definition/build time rather than at the first scheduled fire. The original validator message is embedded in the error text, and details include the offending cron string.
Source
Thrown at packages/core/src/schedules/define.ts:190
details: { label: label ?? '' },
text: `Schedule${where}: set exactly one execution mode — remove either 'prompt' or 'handler'.`,
});
}
if (!hasPrompt && !hasHandler) {
throw new MastraError({
id: 'SCHEDULES_MISSING_MODE',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
details: { label: label ?? '' },
text: `Schedule${where}: set exactly one execution mode — provide a non-empty 'prompt' or a 'handler' function.`,
});
}
try {
validateCron(definition.cron, definition.timezone);
} catch (error) {
throw new MastraError(
{
id: 'SCHEDULES_INVALID_CRON',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
details: { label: label ?? '', cron: String(definition.cron) },
text: `Schedule${where}: ${error instanceof Error ? error.message : String(error)}`,
},
error,
);
}
// Markdown schedules never pass through TypeScript, so these enum-ish fields
// are only checked here. An unchecked value would reach schedule storage and
// surface as a confusing runtime failure on the first fire.
if (definition.signalType !== undefined && !SCHEDULE_SIGNAL_TYPES.includes(definition.signalType)) {
throw new MastraError({
id: 'SCHEDULES_INVALID_SIGNAL_TYPE',
domain: ErrorDomain.AGENT,View on GitHub (pinned to 75dd419e61)
Solutions
- Read the embedded validator message and fix the cron expression accordingly (correct number of fields, in-range values).
- Verify the timezone is a valid IANA name (e.g. 'America/New_York'); remove the timezone field if not needed.
- Test the expression with a cron validator or the same parser library before deploying.
- If the cron is dynamically built, log/inspect the final string — coerced non-string values often produce garbage like 'undefined'.
Example fix
// before
defineSchedule({ cron: '0 9 * ', timezone: 'UTC+2' });
// after
defineSchedule({ cron: '0 9 * * *', timezone: 'UTC' }); Defensive patterns
Strategy: validation
Validate before calling
function isValidCron(cron, timezone) {
try { validateCron(cron, timezone); return true; } catch { return false; }
}
if (!isValidCron('0 9 * * *', 'UTC')) throw new Error('Invalid cron/timezone before defining schedule'); Try / catch
try {
const schedule = defineSchedule({ cron: myCron, timezone: myTz, prompt });
} catch (e) {
if (e instanceof MastraError && e.id === 'SCHEDULES_INVALID_CRON') {
// e.message contains the underlying parser message; log cron and fix the expression
} else throw e;
} Prevention
- Validate cron expressions with a cron parser/validator before committing them.
- Use only valid IANA timezone names (e.g. from Intl.supportedValuesOf('timeZone')).
- Avoid exotic cron syntax (macros, seconds fields) unless the validator documents support.
- For dynamic crons, log the final string and assert it matches /\S+(\s+\S+){4}$/ before use.
When it happens
Trigger: Passing a malformed cron expression (wrong field count, out-of-range values, invalid step/list characters) to defineSchedule or a file-based schedule; passing a cron string paired with an unrecognized IANA timezone; passing a non-string cron value that String()-coerces to something unparseable, via resolveSchedules.
Common situations: Hand-writing a 5-field cron with 6 fields or vice versa when the parser expects one specific format; using '@daily' style macros or seconds fields unsupported by the validator; typo'd timezone like 'UTC+2' or 'America/Orlando' instead of a valid IANA zone; markdown schedules where TS types can't catch the bad value.
Related errors
- SCHEDULES_AMBIGUOUS_MODE
- SCHEDULES_MISSING_MODE
- Google RBAC roleMapping is required.
- Cookie password must be at least 32 characters. Set OKTA_COO
- heartbeatMs must be a finite number no greater than ${MAX_TI
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/4b2528dcce71490e.
Report an issue: GitHub.