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

Open
#36,500 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
rust, sqlite

Research direction

Start by tracing the automation create/update operations through schedule normalization and SQLite persistence, then inspect how next_run_at is computed and exposed. Reproduce the submitted yearly RRULE and compare the requested instant with the persisted next_run_at. Done means the API makes timezone interpretation and the computed next execution visible or rejects an unsafe schedule.

Written by the indexing model from the issue text.

Description

app automations bug
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.

  2. Support an expectedRunAt postcondition. Creation should fail if the calculated execution time differs from the requested instant beyond a small tolerance.

  3. Require an explicit timezone or UTC DTSTART for one-shot calendar schedules containing BYHOUR.

  4. Warn or fail when a newly created one-shot automation resolves far beyond the requested or creation time.

  5. Treat COUNT=1 rules whose current-year occurrence is already past as suspicious instead of silently rolling them into the next year.

  6. Display the computed next execution time immediately in the UI and creation response.

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

Dominant language
Rust
Stars
125k
Forks
19.5k
Avg merge
1m
Merged PRs (30d)
1k

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from openai/codex

All issues in openai/codex

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.