{"record":{"id":"e06a791232e4f11c","repo":"mastra-ai/mastra","slug":"invalid-cron-expression-cron-reason","errorCode":null,"errorMessage":"Invalid cron expression \"${cron}\": ${reason}","messagePattern":"Invalid cron expression \"(.+?)\": (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/scheduler/cron.ts","lineNumber":23,"sourceCode":" *\n * @param cron - Cron expression (5-, 6-, or 7-part).\n * @param timezone - Optional IANA timezone (e.g. 'America/New_York').\n */\nexport function validateCron(cron: string, timezone?: string): void {\n  if (typeof cron !== 'string' || cron.trim() === '') {\n    throw new Error(\n      `Invalid cron expression: expected a non-empty cron string (e.g. \"0 * * * *\"), but received ${cron === undefined ? 'undefined' : JSON.stringify(cron)}.`,\n    );\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.","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/scheduler/cron.ts#L5-L41","documentation":"validateCron throws this when the cron string is non-empty but Croner rejects the pattern itself (e.g. wrong field count, out-of-range values). The original Croner message is included as the reason so the specific syntax problem is visible.","triggerScenarios":"Calling validateCron('99 99 * * *') (out-of-range fields), validateCron('* * *') (too few parts), or any malformed pattern such as '*/foo * * * *' — any input where `new Cron(cron)` throws synchronously.","commonSituations":"Typos in cron fields; using seconds-level 6/7-part syntax incorrectly; copying cron from another system with unsupported syntax; hand-editing schedules in production.","solutions":["Read the embedded reason from Croner and fix the offending field(s) in the expression.","Use a standard 5-part expression (minute hour day month weekday) or a supported 6/7-part form.","Test the pattern with an online cron parser or by running computeNextFireAt to confirm it yields a time.","Keep cron strings in validated config/schema rather than free-form strings."],"exampleFix":"// before\nvalidateCron('0 25 * * *'); // hour 25 is invalid\n// after\nvalidateCron('0 5 * * *');","handlingStrategy":"validation","validationCode":"function preCheckCron(cron: string) {\n  const parts = cron.trim().split(/\\s+/);\n  if (parts.length < 5 || parts.length > 7) throw new Error(`cron must have 5-7 fields, got ${parts.length}: \"${cron}\"`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateCron(cron);\n} catch (e) {\n  const msg = (e as Error).message;\n  if (msg.startsWith('Invalid cron expression \"')) {\n    console.error(`Bad cron pattern: ${cron}. ${msg}`);\n  } else throw e;\n}","preventionTips":["Test cron strings with a parser or computeNextFireAt before deploying","Keep cron expressions in reviewed config, not inline literals","Document the supported 5/6/7-field format for your team","Add cron pattern tests to CI"],"tags":["workflows","scheduler","cron","validation"],"backgroundTag":"invalid-cron-expression","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}