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

  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.