{"record":{"id":"2626140606926077","repo":"mastra-ai/mastra","slug":"cron-expression-cron-has-no-future-occurrence","errorCode":null,"errorMessage":"Cron expression \"${cron}\" has no future occurrence after ${reference.toISOString()}","messagePattern":"Cron expression \"(.+?)\" has no future occurrence after (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/scheduler/cron.ts","lineNumber":53,"sourceCode":"  }\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 });\n  const reference = options?.after !== undefined ? new Date(options.after) : new Date();\n  const next = job.nextRun(reference);\n  if (!next) {\n    throw new Error(`Cron expression \"${cron}\" has no future occurrence after ${reference.toISOString()}`);\n  }\n  return next.getTime();\n}\n","sourceCodeStart":35,"sourceCodeEnd":57,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/scheduler/cron.ts#L35-L57","documentation":"computeNextFireAt throws when Croner's nextRun returns no occurrence after the reference time for the given cron expression (and timezone). This happens for patterns that can never fire again relative to the reference, so the scheduler cannot determine the next fire timestamp.","triggerScenarios":"Calling computeNextFireAt with a cron whose only possible occurrences are in the past relative to options.after or now — e.g. a date-constrained pattern like '0 0 29 2 *' (Feb 29) evaluated far from leap years, or an `after` timestamp beyond all valid occurrences of the pattern.","commonSituations":"Rare/one-shot date patterns combined with a far-future `after`; DST/timezone edge cases where Croner cannot produce a next run; passing `after` from stale persisted state.","solutions":["Check that the cron expression can actually recur in the future (avoid date-pinned patterns for recurring schedules).","Verify options.after is a sensible timestamp (not far in the future or wrong unit, e.g. seconds vs ms).","Simplify the pattern or pick a different recurrence that has future occurrences.","Catch this error and fall back to a default or disable the schedule."],"exampleFix":"// before\ncomputeNextFireAt('0 0 29 2 *', { after: Date.parse('2030-03-01') });\n// after\ncomputeNextFireAt('0 0 * * *', { after: Date.now() });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let fireAt: number;\ntry {\n  fireAt = computeNextFireAt(cron, { timezone, after: Date.now() });\n} catch (e) {\n  if ((e as Error).message.includes('has no future occurrence')) {\n    fireAt = Date.now() + 60_000; // fallback or disable schedule\n  } else throw e;\n}","preventionTips":["Avoid date-pinned cron patterns (e.g. Feb 29) for recurring schedules","Ensure `after` timestamps are in milliseconds and not in the far future","Compute the next fire time immediately after creating a schedule to fail fast","Catch and log this error when loading persisted schedules"],"tags":["workflows","scheduler","cron","scheduling"],"backgroundTag":"no-next-cron-occurrence","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}