Skip to content

fix(effect): stop Schedule.cron crashing on a non-finite clock#6296

Open
eldardada wants to merge 1 commit into
Effect-TS:mainfrom
eldardada:fix/schedule-cron-non-finite-now
Open

fix(effect): stop Schedule.cron crashing on a non-finite clock#6296
eldardada wants to merge 1 commit into
Effect-TS:mainfrom
eldardada:fix/schedule-cron-non-finite-now

Conversation

@eldardada

Copy link
Copy Markdown

Resolves #6292.

Problem

Advancing the clock past the end of time, e.g. TestClock.adjust(Infinity), crashes a running Schedule.cron with an uncaught IllegalArgumentException: Invalid date that kills the fiber:

IllegalArgumentException: Invalid date
  at unsafeFromDate (internal/dateTime.ts)
  at unsafeMakeZoned (internal/dateTime.ts)
  at match (Cron.ts)
  at ScheduleImpl.step (internal/schedule.ts)

Cause

The cron schedule step turns the current time into a Date and runs calendar math on it:

const date = new Date(now)
if (initial && Cron.match(cron, date)) { ... }
next = Cron.next(cron, date).getTime()

When now is non-finite, new Date(now) is an Invalid Date. Cron.match / Cron.next then call dateTime.unsafeMakeZoned, whose date.getTime() is NaN, and unsafeFromDate throws by design. So the real bug is that Schedule.cron hands an invalid instant to the cron helpers.

Time-based neighbours like Schedule.fixed and Schedule.spaced do not crash here: they work with plain now + delay arithmetic and never build a Date, so a non-finite now just flows through.

Fix

Guard the cron step: when now is non-finite there is no instant to match, so finish the schedule (ScheduleDecision.done) instead of throwing. This brings cron in line with how the other time-based schedules behave when the clock runs past the end of time, and leaves all finite behaviour untouched.

Verification

Reproduced the crash deterministically (cron fails while fixed / spaced succeed under the same now = Infinity), confirmed the fix turns the failure into a clean Success, and added a regression test in the cron suite. pnpm check (tsc), eslint, and the full Schedule test suite (83 tests) all pass. Changeset included (effect: patch).

When the clock is advanced past the end of time (e.g. TestClock.adjust(Infinity)),
the cron schedule received a non-finite now. new Date(now) is then an Invalid Date,
which made the internal Cron.match/Cron.next calls throw IllegalArgumentException and
crash the fiber. Finish the schedule instead, matching how Schedule.fixed and
Schedule.spaced already behave in that case.
@changeset-bot

changeset-bot Bot commented Jun 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 63211d3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
effect Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

Cron + TestClock.adjust(Infinity) results in invalid date crash

1 participant