{"record":{"id":"6f6680c714747175","repo":"affaan-m/ECC","slug":"cron-expression-expr-did-not-yield-a-future-ru","errorCode":null,"errorMessage":"cron expression `{expr}` did not yield a future run time","messagePattern":"cron expression `(.+?)` did not yield a future run time","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/session/manager.rs","lineNumber":2382,"sourceCode":"        fields => {\n            anyhow::bail!(\n                \"invalid cron expression `{trimmed}`: expected 5, 6, or 7 fields but found {fields}\"\n            )\n        }\n    };\n    CronSchedule::from_str(&normalized)\n        .with_context(|| format!(\"invalid cron expression `{trimmed}`\"))\n}\n\nfn next_schedule_run_at(\n    expr: &str,\n    after: chrono::DateTime<chrono::Utc>,\n) -> Result<chrono::DateTime<chrono::Utc>> {\n    parse_cron_schedule(expr)?\n        .after(&after)\n        .next()\n        .map(|value| value.with_timezone(&chrono::Utc))\n        .ok_or_else(|| anyhow::anyhow!(\"cron expression `{expr}` did not yield a future run time\"))\n}\n\npub async fn run_session(\n    cfg: &Config,\n    session_id: &str,\n    task: &str,\n    agent_type: &str,\n    working_dir: &Path,\n) -> Result<()> {\n    let db = StateStore::open(&cfg.db_path)?;\n    let session = resolve_session(&db, session_id)?;\n\n    if session.state != SessionState::Pending {\n        tracing::info!(\n            \"Skipping run_session for {} because state is {}\",\n            session_id,\n            session.state\n        );","sourceCodeStart":2364,"sourceCodeEnd":2400,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/session/manager.rs#L2364-L2400","documentation":"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.","triggerScenarios":"Calling next_schedule_run_at with a valid cron expression whose CronSchedule iterator returns None for .after(&after).next().","commonSituations":"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.","solutions":["Test the cron expression with a standalone cron parser to verify it produces future dates","Check for impossible date constraints like '0 0 31 2 *' (February 31st)","If the expression references a specific year that has passed, remove the year field or update it","Validate the schedule at config-load time by computing the next run and failing early"],"exampleFix":"// before\nlet schedule = \"0 0 31 2 *\";  // Feb 31 — impossible date\nlet next = next_schedule_run_at(schedule, Utc::now())?;\n\n// after\nlet schedule = \"0 0 1 3 *\";  // March 1st — valid\nlet next = next_schedule_run_at(schedule, Utc::now())?;","handlingStrategy":"validation","validationCode":"fn cron_has_future_run(expr: &str, after: DateTime<Utc>) -> bool {\n    parse_cron_schedule(expr)\n        .ok()\n        .and_then(|sched| sched.after(&after).next())\n        .is_some()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Test cron expressions with a future-date computation before persisting them in config","Check for impossible date constraints (Feb 31, Apr 31, etc.) in schedule fields","Validate schedules at config-load time by computing the next run"],"tags":["cron","scheduling","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}