affaan-m/ECC · error

cron expression ` ` did not yield a future run time

Error message

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

What it means

Raised when a parsed cron expression cannot produce any next run time after the given anchor. Valid-looking expressions may still be unsatisfiable, e.g. Feb 30, or dates excluded by day-of-month/day-of-week restrictions. The scheduler refuses to register a schedule it can never fire.

Solutions

  1. Validate the cron expression with a checker before scheduling; remove impossible date fields (Feb 30)
  2. Use a simpler expression (e.g. daily wildcard) to confirm scheduling works, then tighten it
  3. Check that day-of-month and day-of-week fields are not mutually restrictive (use * in one)

Example fix

// before
schedule: "0 0 30 2 *"   // Feb 30 never exists
// after
schedule: "0 0 1 3 *"    // March 1st instead
Defensive patterns

Strategy: validation

Validate before calling

use cron::Schedule;
let sched: Schedule = expr.parse()?;
if sched.after(&chrono::Utc::now()).next().is_none() {
    anyhow::bail!("cron `{expr}` has no future occurrence");
}

Try / catch

match next_cron_run(expr, now) {
    Ok(t) => schedule_at(t),
    Err(e) => eprintln!("bad schedule: {e}; fix the cron expression"),
}

Prevention

When it happens

Trigger: Scheduling a session with a cron expression whose next occurrence after `now` does not exist (e.g. '0 0 30 2 *' — Feb 30) or whose only matching dates are in the past.

Common situations: Hand-written cron strings with impossible dates; copy-pasted cron from another tool using 6/7-field syntax with seconds misaligned; time-zone assumptions making the expected first run already past.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/6f6680c714747175. Report an issue: GitHub.

Appendix: 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 8321021c54)