Skip to content

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

Description

@Hackerokuz

What version of Effect is running?

^3.21.4

What steps can reproduce the bug?

npm install effect
npm install --dev typescript

My package.json

{
  "name": "test",
  "dependencies": {
    "effect": "^3.21.4"
  },
  "devDependencies": {
    "typescript": "^6.0.3"
  }
}

My tsconfig.json

{
  // Visit https://aka.ms/tsconfig to read more about this file
  "compilerOptions": {
    // File Layout
    // "rootDir": "./src",
    // "outDir": "./dist",

    // Environment Settings
    // See also https://aka.ms/tsconfig/module
    "module": "nodenext",
    "target": "esnext",
    "types": [],
    // For nodejs:
    // "lib": ["esnext"],
    // "types": ["node"],
    // and npm install -D @types/node

    // Other Outputs
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,

    // Stricter Typechecking Options
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,

    // Style Options
    // "noImplicitReturns": true,
    // "noImplicitOverride": true,
    // "noUnusedLocals": true,
    // "noUnusedParameters": true,
    // "noFallthroughCasesInSwitch": true,
    // "noPropertyAccessFromIndexSignature": true,

    // Recommended Options
    "strict": true,
    "jsx": "react-jsx",
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "noUncheckedSideEffectImports": true,
    "moduleDetection": "force",
    "skipLibCheck": true,
  }
}

My src/index.ts

import {
  Effect,
  Schedule,
  TestClock,
  Fiber,
  TestContext,
  Cron,
  Console
} from "effect";

// A helper function to log output at each interval of the schedule
const log = <A>(
  action: Effect.Effect<A>,
  schedule: Schedule.Schedule<[number, number], void>
): void => {
  let i = 0

  Effect.gen(function* () {
    const fiber: Fiber.RuntimeFiber<[[number, number], number]> =
      yield* Effect.gen(function* () {
        yield* action
        i++
      }).pipe(
        Effect.repeat(
          schedule.pipe(
            // Limit the number of iterations for the example
            Schedule.intersect(Schedule.recurs(10)),
            Schedule.tapOutput(([Out]) =>
              Console.log(
                i === 11 ? "..." : [new Date(Out[0]), new Date(Out[1])]
              )
            )
          )
        ),
        Effect.fork
      )
    yield* TestClock.adjust(Infinity)
    yield* Fiber.join(fiber)
  }).pipe(Effect.provide(TestContext.TestContext), Effect.runPromise)
}

// Build a cron that triggers at 4:00 AM
// on the 8th to the 14th of each month
const cron = Cron.unsafeParse("0 0 4 8-14 * *", "UTC")

// Convert the Cron into a Schedule
const schedule = Schedule.cron(cron)

// Define a dummy action to repeat
const action = Effect.tryPromise(() => {
  console.log('started');
  // Simulate work
  return new Promise(resolve => setTimeout(resolve, 500));
}).pipe(Effect.andThen(Console.log('Done')), Effect.catchAll(e => Console.error(e)));

// Log the schedule intervals
log(action, schedule)
/*
Output:
Started
Done
IllegalArgumentException: Invalid date
*/

npx tsx src/index.ts

What is the expected behavior?

Simulate time progression and run cron jobs without crashing

What do you see instead?

started
Done
node:internal/process/promises:394
    triggerUncaughtException(err, true /* fromPromise */);
    ^

IllegalArgumentException: Invalid date
    at date (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/dateTime.ts:218:11)
    at input (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/dateTime.ts:228:12)
    at Object.unsafeMakeZoned (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/dateTime.ts:253:16)
    at Object.match (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/Cron.ts:389:26)
    at ScheduleImpl.step (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:501:27)
    at ScheduleImpl.step (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:896:16)
    at ScheduleImpl.step (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:1439:14)
    at <anonymous> (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:173:48)
    at <anonymous> (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/fiberRuntime.ts:1353:34)
    at body (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/Utils.ts:786:14) {
  name: '(FiberFailure) IllegalArgumentException',
  Symbol(effect/Runtime/FiberFailure): Symbol(effect/Runtime/FiberFailure),
  Symbol(effect/Runtime/FiberFailure/Cause): {
    _tag: 'Die',
    defect: IllegalArgumentException: Invalid date
        at date (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/dateTime.ts:218:11)
        at input (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/dateTime.ts:228:12)
        at Object.unsafeMakeZoned (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/dateTime.ts:253:16)
        at Object.match (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/Cron.ts:389:26)
        at ScheduleImpl.step (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:501:27)
        at ScheduleImpl.step (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:896:16)
        at ScheduleImpl.step (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:1439:14)
        at EffectPrimitive.commit (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/schedule.ts:173:48)
        at <anonymous> (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/internal/fiberRuntime.ts:1353:34)
        at body (/home/h/InternalStorage/Programming/WebDevelopment/open-source/test-yarn/node_modules/effect/src/Utils.ts:786:14) {
      _tag: 'IllegalArgumentException'
    }
  }
}

Node.js v24.13.1
Image

Additional information

My package.json

{
  "name": "test",
  "dependencies": {
    "effect": "^3.21.4"
  },
  "devDependencies": {
    "typescript": "^6.0.3"
  }
}

My tsconfig.json

{
  // Visit https://aka.ms/tsconfig to read more about this file
  "compilerOptions": {
    // File Layout
    // "rootDir": "./src",
    // "outDir": "./dist",

    // Environment Settings
    // See also https://aka.ms/tsconfig/module
    "module": "nodenext",
    "target": "esnext",
    "types": [],
    // For nodejs:
    // "lib": ["esnext"],
    // "types": ["node"],
    // and npm install -D @types/node

    // Other Outputs
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,

    // Stricter Typechecking Options
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,

    // Style Options
    // "noImplicitReturns": true,
    // "noImplicitOverride": true,
    // "noUnusedLocals": true,
    // "noUnusedParameters": true,
    // "noFallthroughCasesInSwitch": true,
    // "noPropertyAccessFromIndexSignature": true,

    // Recommended Options
    "strict": true,
    "jsx": "react-jsx",
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "noUncheckedSideEffectImports": true,
    "moduleDetection": "force",
    "skipLibCheck": true,
  }
}

Node.js v24.13.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions