mastra-ai/mastra · error

Invalid timezone "${timezone}": ${reason}

Error message

Invalid timezone "${timezone}": ${reason}

What it means

validateCron throws this when the optional timezone argument is not a valid IANA timezone. Croner only surfaces timezone problems lazily when a fire time is computed, so validateCron explicitly computes nextRun with the timezone to catch and label it here.

Source

Thrown at packages/core/src/workflows/scheduler/cron.ts:31

    );
  }
  // Croner throws synchronously on an invalid pattern when the job is
  // constructed. Validate the pattern on its own first so timezone problems
  // (which croner only surfaces lazily) are not mislabeled as cron errors.
  let job: Cron;
  try {
    job = new Cron(cron);
  } catch (error) {
    const reason = error instanceof Error ? error.message : String(error);
    throw new Error(`Invalid cron expression "${cron}": ${reason}`);
  }
  // The timezone is only exercised when a fire time is computed.
  if (timezone !== undefined) {
    try {
      new Cron(cron, { timezone }).nextRun();
    } catch (error) {
      const reason = error instanceof Error ? error.message : String(error);
      throw new Error(`Invalid timezone "${timezone}": ${reason}`);
    }
  } else {
    job.nextRun();
  }
}

/**
 * Compute the next fire time (ms since epoch) for a cron expression.
 *
 * @param cron - Cron expression.
 * @param options - Optional timezone and reference time (`after`, ms since epoch).
 *   The next fire time is the first cron occurrence strictly after `after`.
 *   Defaults to `Date.now()`.
 * @returns The next fire time in ms since epoch.
 * @throws If the cron expression is invalid or has no future occurrence.
 */
export function computeNextFireAt(cron: string, options?: { timezone?: string; after?: number }): number {
  const job = new Cron(cron, { timezone: options?.timezone });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use a valid IANA timezone string like 'America/New_York' or 'Europe/Berlin'.
  2. Check the embedded reason — the original Croner error names the bad timezone.
  3. Validate against Intl.supportedValuesOf('timeZone') before calling.
  4. Omit the timezone parameter if UTC is acceptable.

Example fix

// before
validateCron('0 * * * *', 'EST');
// after
validateCron('0 * * * *', 'America/New_York');
Defensive patterns

Strategy: validation

Validate before calling

function isIANATimezone(tz: string): boolean {
  try { new Intl.DateTimeFormat('en-US', { timeZone: tz }); return true; } catch { return false; }
}

Type guard

function isValidTimezone(tz: unknown): tz is string {
  return typeof tz === 'string' && (() => { try { new Intl.DateTimeFormat('en-US', { timeZone: tz }); return true; } catch { return false; } })();
}

Try / catch

try {
  validateCron(cron, timezone);
} catch (e) {
  if ((e as Error).message.startsWith('Invalid timezone')) {
    timezone = 'UTC';
  } else throw e;
}

Prevention

When it happens

Trigger: Calling validateCron('0 * * * *', 'America/New_York ') with a typo ('America/News_York'), a non-IANA name ('EST'), or a locale-style offset ('UTC+2'); computing nextRun with that timezone throws and is rethrown as this error.

Common situations: Hardcoded abbreviations instead of IANA names; mis-typed timezone from user config; timezone names taken from OS-specific databases that differ from the IANA set.

Related errors


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