Hmbown/CodeWhale · error · anyhow::Error
fire_at must be in the future (got {}, now is {})
Error message
fire_at must be in the future (got {}, now is {}) What it means
create_trigger requires fire_at to be strictly greater than Utc::now() at creation time; equality also fails. The error echoes both timestamps in RFC3339 so clock skew or a stale payload is visible in the message itself.
Source
Thrown at crates/tui/src/automation_manager.rs:1329
if matches!(
run.status,
AutomationRunStatus::Queued | AutomationRunStatus::Running
) && run.task_id.is_some()
{
pending.push(run);
}
}
}
Ok(pending)
}
// ── Delayed-trigger storage methods ──────────────────────────────────
/// Persist a new delayed trigger and return the record.
pub fn create_trigger(&self, req: CreateDelayedTriggerRequest) -> Result<DelayedTriggerRecord> {
let now = Utc::now();
if req.fire_at <= now {
bail!(
"fire_at must be in the future (got {}, now is {})",
req.fire_at.to_rfc3339(),
now.to_rfc3339()
);
}
if req.message.trim().is_empty() {
bail!("Trigger message must not be empty");
}
let record = DelayedTriggerRecord {
schema_version: CURRENT_TRIGGER_SCHEMA_VERSION,
trigger_id: format!("trig_{}", Uuid::new_v4().simple()),
fire_at: req.fire_at,
message: req.message.trim().to_string(),
workspace: req.workspace,
owner_session_id: req.owner_session_id,
status: DelayedTriggerStatus::Pending,
created_at: now,
fired_at: None,View on GitHub (pinned to 0c42157ee5)
Solutions
- Compute fire_at as Utc::now() + delay at submission time, not earlier
- Drop stored requests whose fire_at has passed instead of replaying them
- Sync the system clock (NTP) if the printed 'now' disagrees with expectation
- Add a minimum lead (e.g. +30 seconds) to absorb processing delay
Example fix
// before let fire_at = chrono::Utc::now() - chrono::Duration::minutes(5); // after let fire_at = chrono::Utc::now() + chrono::Duration::hours(1);
Defensive patterns
Strategy: validation
Validate before calling
fn fire_at_submittable(fire_at: chrono::DateTime<chrono::Utc>) -> bool {
fire_at > chrono::Utc::now() + chrono::Duration::seconds(1) // small lead for safety
} Type guard
fn is_future_timestamp(t: chrono::DateTime<chrono::Utc>) -> bool { t > chrono::Utc::now() } Try / catch
match manager.create_trigger(req) {
Ok(trig) => { /* ... */ }
Err(e) if e.to_string().contains("must be in the future") => {
// Drop or recompute the timestamp; do not blind-retry the same payload.
}
Err(e) => return Err(e),
} Prevention
- Compute fire_at from Utc::now() at submission time, never reuse stale values
- Drop queued requests whose fire_at has already passed
- Keep system clocks NTP-synced; the error message prints both timestamps for comparison
- Add a minimum lead (e.g. 30 seconds) to absorb processing delay
When it happens
Trigger: Passing a fire_at already in the past; recomputing fire_at from a clock that is behind; replaying a stored CreateDelayedTriggerRequest after its time has passed; passing exactly now.
Common situations: Retry queues replaying old requests; VMs or containers with drifted clocks; naive local times parsed as UTC and shifted into the past.
Related errors
- Failed to parse ONCE AT '{trimmed}'. Use local YYYY-MM-DDTHH
- Trigger message must not be empty
- context_window must be greater than 0
- custom provider '{provider_id}' must set [providers.{provide
- unknown field '{field_key}' for built-in provider '{provider
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/14cac830012beaa1.
Report an issue: GitHub.