mastra-ai/mastra · error

Cron expression "${cron}" has no future occurrence after ${r

Error message

Cron expression "${cron}" has no future occurrence after ${reference.toISOString()}

What it means

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.

Source

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

  }
}

/**
 * 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 });
  const reference = options?.after !== undefined ? new Date(options.after) : new Date();
  const next = job.nextRun(reference);
  if (!next) {
    throw new Error(`Cron expression "${cron}" has no future occurrence after ${reference.toISOString()}`);
  }
  return next.getTime();
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check that the cron expression can actually recur in the future (avoid date-pinned patterns for recurring schedules).
  2. Verify options.after is a sensible timestamp (not far in the future or wrong unit, e.g. seconds vs ms).
  3. Simplify the pattern or pick a different recurrence that has future occurrences.
  4. Catch this error and fall back to a default or disable the schedule.

Example fix

// before
computeNextFireAt('0 0 29 2 *', { after: Date.parse('2030-03-01') });
// after
computeNextFireAt('0 0 * * *', { after: Date.now() });
Defensive patterns

Strategy: try-catch

Try / catch

let fireAt: number;
try {
  fireAt = computeNextFireAt(cron, { timezone, after: Date.now() });
} catch (e) {
  if ((e as Error).message.includes('has no future occurrence')) {
    fireAt = Date.now() + 60_000; // fallback or disable schedule
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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