Hmbown/CodeWhale · error
ONCE local time does not exist: {trimmed}
Error message
ONCE local time does not exist: {trimmed} What it means
AT values without an offset are read as local wall time and mapped through resolve_local_datetime; the mapping returns None exactly when that wall-clock reading never existed locally — a time inside a DST spring-forward gap. Unlike HOURLY anchors (which silently skip nonexistent clock times), ONCE refuses to guess a different fire time for your one-shot and errors, naming the offending timestamp.
Source
Thrown at crates/tui/src/automation_manager.rs:631
let expr = parts
.get("EXPR")
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.ok_or_else(|| anyhow::anyhow!("CRON schedules require EXPR"))?;
ParsedCronExpr::parse(&expr)?;
Ok(AutomationSchedule::Cron { expr })
}
fn parse_once_at(raw: &str) -> Result<DateTime<Utc>> {
let trimmed = raw.trim();
if let Ok(at) = DateTime::parse_from_rfc3339(trimmed) {
return Ok(at.with_timezone(&Utc));
}
for format in ["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M"] {
if let Ok(naive) = NaiveDateTime::parse_from_str(trimmed, format) {
return resolve_local_datetime(&Local, naive)
.map(|value| value.with_timezone(&Utc))
.ok_or_else(|| anyhow::anyhow!("ONCE local time does not exist: {trimmed}"));
}
}
bail!("Failed to parse ONCE AT '{trimmed}'. Use local YYYY-MM-DDTHH:MM[:SS] or RFC3339")
}
#[derive(Debug, Clone)]
struct ParsedCronExpr {
minute: CronField,
hour: CronField,
day_of_month: CronField,
month: CronField,
day_of_week: CronField,
}
impl ParsedCronExpr {
fn parse(expr: &str) -> Result<Self> {
let fields: Vec<&str> = expr.split_whitespace().collect();
if fields.len() != 5 {View on GitHub (pinned to 8880682c63)
Solutions
- Use RFC3339 with an explicit offset/UTC: AT=2026-03-08T06:30:00Z
- Or pick a local time outside the gap (e.g. 03:30 after the jump)
- Pre-validate local AT strings with Local.from_local_datetime(naive).single().is_some() before persisting
Example fix
// before (America/New_York: 02:30 never exists on 2026-03-08) let rrule = "FREQ=ONCE;AT=2026-03-08T02:30"; // after let rrule = "FREQ=ONCE;AT=2026-03-08T06:30:00Z";
Defensive patterns
Strategy: validation
Validate before calling
let trimmed = at_raw.trim();
if chrono::DateTime::parse_from_rfc3339(trimmed).is_err() {
let naive = chrono::NaiveDateTime::parse_from_str(trimmed, "%Y-%m-%dT%H:%M:%S")
.or_else(|_| chrono::NaiveDateTime::parse_from_str(trimmed, "%Y-%m-%dT%H:%M"))?;
if chrono::Local.from_local_datetime(&naive).single().is_none() {
anyhow::bail!("local time {trimmed} does not exist (DST spring-forward gap); use an RFC3339 time with offset");
}
} Type guard
fn once_local_time_exists(raw: &str) -> bool {
let trimmed = raw.trim();
if chrono::DateTime::parse_from_rfc3339(trimmed).is_ok() {
return true; // explicit offset never hits the gap
}
["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M"]
.iter()
.find_map(|f| chrono::NaiveDateTime::parse_from_str(trimmed, f).ok())
.is_none_or(|naive| chrono::Local.from_local_datetime(&naive).single().is_some())
} Prevention
- Prefer RFC3339 with an explicit offset (or UTC 'Z') for one-shot times; it bypasses local-time resolution entirely
- Avoid scheduling one-shots inside the 02:00-03:00 window on spring-forward days in DST jurisdictions
- Pre-validate local AT strings with Local.from_local_datetime(...).single().is_some() before persisting
- Remember the scheduler's timezone is the server's Local — author times with that in mind
When it happens
Trigger: AT=2026-03-08T02:30 in a US timezone where clocks jump 02:00->03:00 that day; any local naive time that a forward offset transition skipped. RFC3339 inputs with an explicit offset never hit this path.
Common situations: One-shot automations placed at 2:00-2:59 AM on the spring-forward date; servers in a different timezone than the schedule author; tz-database rule changes moving the gap.
Related errors
- WEEKLY schedules require BYDAY
- WEEKLY schedules require BYHOUR
- WEEKLY schedules require BYMINUTE
- ONCE schedules require AT
- Unable to construct HOURLY anchor
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/4b2b45a985ecaa41.
Report an issue: GitHub.