{"record":{"id":"716143895c717fe8","repo":"mastra-ai/mastra","slug":"invalid-timezone-timezone-reason","errorCode":null,"errorMessage":"Invalid timezone \"${timezone}\": ${reason}","messagePattern":"Invalid timezone \"(.+?)\": (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/scheduler/cron.ts","lineNumber":31,"sourceCode":"    );\n  }\n  // Croner throws synchronously on an invalid pattern when the job is\n  // constructed. Validate the pattern on its own first so timezone problems\n  // (which croner only surfaces lazily) are not mislabeled as cron errors.\n  let job: Cron;\n  try {\n    job = new Cron(cron);\n  } catch (error) {\n    const reason = error instanceof Error ? error.message : String(error);\n    throw new Error(`Invalid cron expression \"${cron}\": ${reason}`);\n  }\n  // The timezone is only exercised when a fire time is computed.\n  if (timezone !== undefined) {\n    try {\n      new Cron(cron, { timezone }).nextRun();\n    } catch (error) {\n      const reason = error instanceof Error ? error.message : String(error);\n      throw new Error(`Invalid timezone \"${timezone}\": ${reason}`);\n    }\n  } else {\n    job.nextRun();\n  }\n}\n\n/**\n * Compute the next fire time (ms since epoch) for a cron expression.\n *\n * @param cron - Cron expression.\n * @param options - Optional timezone and reference time (`after`, ms since epoch).\n *   The next fire time is the first cron occurrence strictly after `after`.\n *   Defaults to `Date.now()`.\n * @returns The next fire time in ms since epoch.\n * @throws If the cron expression is invalid or has no future occurrence.\n */\nexport function computeNextFireAt(cron: string, options?: { timezone?: string; after?: number }): number {\n  const job = new Cron(cron, { timezone: options?.timezone });","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/scheduler/cron.ts#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use a valid IANA timezone string like 'America/New_York' or 'Europe/Berlin'.","Check the embedded reason — the original Croner error names the bad timezone.","Validate against Intl.supportedValuesOf('timeZone') before calling.","Omit the timezone parameter if UTC is acceptable."],"exampleFix":"// before\nvalidateCron('0 * * * *', 'EST');\n// after\nvalidateCron('0 * * * *', 'America/New_York');","handlingStrategy":"validation","validationCode":"function isIANATimezone(tz: string): boolean {\n  try { new Intl.DateTimeFormat('en-US', { timeZone: tz }); return true; } catch { return false; }\n}","typeGuard":"function isValidTimezone(tz: unknown): tz is string {\n  return typeof tz === 'string' && (() => { try { new Intl.DateTimeFormat('en-US', { timeZone: tz }); return true; } catch { return false; } })();\n}","tryCatchPattern":"try {\n  validateCron(cron, timezone);\n} catch (e) {\n  if ((e as Error).message.startsWith('Invalid timezone')) {\n    timezone = 'UTC';\n  } else throw e;\n}","preventionTips":["Always use full IANA names (Continent/City), never abbreviations like EST","Validate timezone against Intl.supportedValuesOf('timeZone') at config load","Default to 'UTC' when timezone is optional and unverified","Avoid OS-specific zone names that differ from the IANA database"],"tags":["workflows","scheduler","cron","timezone"],"backgroundTag":"invalid-timezone","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}