affaan-m/ECC · error · anyhow::Error

cron expression `{expr}` did not yield a future run time

Error message

cron expression `{expr}` did not yield a future run time

What it means

The next_schedule_run_at function parses a cron expression and calls .after(&after).next() to find the next future occurrence. If the iterator yields None — meaning no future run time exists for the given expression relative to the current time — the function bails. This is distinct from a parse error: the expression is syntactically valid but produces no future triggers.

Source

Thrown at ecc2/src/session/manager.rs:2382

        fields => {
            anyhow::bail!(
                "invalid cron expression `{trimmed}`: expected 5, 6, or 7 fields but found {fields}"
            )
        }
    };
    CronSchedule::from_str(&normalized)
        .with_context(|| format!("invalid cron expression `{trimmed}`"))
}

fn next_schedule_run_at(
    expr: &str,
    after: chrono::DateTime<chrono::Utc>,
) -> Result<chrono::DateTime<chrono::Utc>> {
    parse_cron_schedule(expr)?
        .after(&after)
        .next()
        .map(|value| value.with_timezone(&chrono::Utc))
        .ok_or_else(|| anyhow::anyhow!("cron expression `{expr}` did not yield a future run time"))
}

pub async fn run_session(
    cfg: &Config,
    session_id: &str,
    task: &str,
    agent_type: &str,
    working_dir: &Path,
) -> Result<()> {
    let db = StateStore::open(&cfg.db_path)?;
    let session = resolve_session(&db, session_id)?;

    if session.state != SessionState::Pending {
        tracing::info!(
            "Skipping run_session for {} because state is {}",
            session_id,
            session.state
        );

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Test the cron expression with a standalone cron parser to verify it produces future dates
  2. Check for impossible date constraints like '0 0 31 2 *' (February 31st)
  3. If the expression references a specific year that has passed, remove the year field or update it
  4. Validate the schedule at config-load time by computing the next run and failing early

Example fix

// before
let schedule = "0 0 31 2 *";  // Feb 31 — impossible date
let next = next_schedule_run_at(schedule, Utc::now())?;

// after
let schedule = "0 0 1 3 *";  // March 1st — valid
let next = next_schedule_run_at(schedule, Utc::now())?;
Defensive patterns

Strategy: validation

Validate before calling

fn cron_has_future_run(expr: &str, after: DateTime<Utc>) -> bool {
    parse_cron_schedule(expr)
        .ok()
        .and_then(|sched| sched.after(&after).next())
        .is_some()
}

Prevention

When it happens

Trigger: Calling next_schedule_run_at with a valid cron expression whose CronSchedule iterator returns None for .after(&after).next().

Common situations: Cron expression with an impossible date constraint (e.g., Feb 31). Expression bounded by year that has already passed. Edge case in the cron crate where certain field combinations produce an empty iteration.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/6f6680c714747175. Report an issue: GitHub.