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.

Solutions

  1. Read the embedded validator message and fix the cron expression accordingly (correct number of fields, in-range values).
  2. Verify the timezone is a valid IANA name (e.g. 'America/New_York'); remove the timezone field if not needed.
  3. Test the expression with a cron validator or the same parser library before deploying.
  4. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/4b2528dcce71490e. Report an issue: GitHub.

Appendix: 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)