One-shot Codex automation silently scheduled one year late due to timezone-ambiguous RRULE

Open 💬 1 comment Opened Aug 1, 2026 by iAchilles
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

26.727.51351 build 6119

What subscription do you have?

PRO X20

What platform is your computer?

macOS: 26.5.2 build 25F84

What issue are you seeing?

-

What steps can reproduce the bug?

-

What is the expected behavior?

The automation was created at:
2026-08-01T06:09:06Z

It was intended to run at:
2026-08-01T06:17:03Z
2026-08-01 02:17:03 America/Santiago

Submitted schedule
RRULE:FREQ=YEARLY;COUNT=1;BYMONTH=8;BYMONTHDAY=1;BYHOUR=2;BYMINUTE=17;BYSECOND=3
The rule contained neither an explicit TZID nor an explicit DTSTART.

Additional information

Summary

A critical heartbeat automation was created successfully in Codex Desktop, but it never ran at the requested time. The automation was intended to wake a task eight minutes later. Instead, its next execution was silently scheduled for August 1, 2027.

This was not a scheduler crash. The scheduler followed the persisted schedule. The immediate caller error was constructing a timezone-less RRULE using local clock fields. However, the automation API made this failure unsafe and difficult to detect: it accepted the rule, returned a generic success response, and did not expose the normalized schedule or computed nextRunAt.

Environment

  • Codex Desktop: 26.727.51351, build 6119
  • Codex CLI: 0.146.0-alpha.9.2
  • macOS: 26.5.2 build 25F84
  • Local timezone: America/Santiago, UTC−04:00

Expected behavior

The automation was created at:

2026-08-01T06:09:06Z

It was intended to run at:

2026-08-01T06:17:03Z
2026-08-01 02:17:03 America/Santiago

Submitted schedule

RRULE:FREQ=YEARLY;COUNT=1;BYMONTH=8;BYMONTHDAY=1;BYHOUR=2;BYMINUTE=17;BYSECOND=3

The rule contained neither an explicit TZID nor an explicit DTSTART.

Actual behavior

The API returned only:

Created automation in the app.

The persisted automation state was:

status:       ACTIVE
next_run_at:  1817086623000
next_run_utc: 2027-08-01 02:17:03
last_run_at:  NULL

The automation had zero execution records. The application was running at the intended time, but no dispatcher or executor attempt occurred because the stored schedule was not due until 2027.

Root cause

The direct cause was a timezone mismatch:

  1. The caller encoded the local hour, 02:17, in an RRULE without TZID.
  2. With no explicit DTSTART, Codex supplied a start point and interpreted the calendar fields against UTC.
  3. 02:17Z on August 1, 2026 was already in the past when the automation was created at 06:09Z.
  4. Because the rule was yearly and limited to one occurrence, the next valid future occurrence became August 1, 2027.

The primary construction mistake was therefore on the agent side: a local wall-clock time was placed into a timezone-ambiguous rule.

The product/API amplified that mistake into a silent reliability failure. Creation succeeded without returning the canonical schedule, timezone, or calculated next execution time. The caller had no postcondition by which to verify that the requested and persisted execution times matched.

Impact

The automation was guarding an external review boundary in an autonomous engineering workflow. The false success signal caused the workflow to remain idle for approximately nine hours despite the required external approval already being available.

This failure mode is particularly dangerous for autonomous workflows because:

  • the automation appears active;
  • no error is emitted;
  • no missed-run notification occurs;
  • the task can remain unattended indefinitely;
  • the actual next run may be months or years away.

Recommended changes

  1. Return the normalized nextRunAt, effective timezone, and canonical DTSTART from every create and update operation.
  1. Support an expectedRunAt postcondition. Creation should fail if the calculated execution time differs from the requested instant beyond a small tolerance.
  1. Require an explicit timezone or UTC DTSTART for one-shot calendar schedules containing BYHOUR.
  1. Warn or fail when a newly created one-shot automation resolves far beyond the requested or creation time.
  1. Treat COUNT=1 rules whose current-year occurrence is already past as suspicious instead of silently rolling them into the next year.
  1. Display the computed next execution time immediately in the UI and creation response.
  1. Add telemetry for large differences between the requested time and normalized nextRunAt.

Related issue

During later cleanup, the automation-management handler became unavailable. Removing the automation definition stopped scheduler enumeration, but an orphaned ACTIVE row remained in SQLite. This was not the cause of the missed run, but it indicates a separate consistency and cleanup issue.

Mitigation applied

Critical review waits no longer rely on detached heartbeat automations. The workflow now uses an active, bounded wait loop with explicit polling and visible progress. This avoids timezone normalization ambiguity and ensures that the task itself remains responsible for observing the review gate.

View original on GitHub ↗

1 Comment

github-actions[bot] contributor · 26 days ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #35791

Powered by Codex Action