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

invalid cron expression

Error message

invalid cron expression `{trimmed}`: expected 5, 6, or 7 fields but found {fields}

What it means

`validate_schedule_cron_expr` counts whitespace-separated fields in the cron expression and requires 5 (minute-based, auto-prefixed with seconds `0 `), 6, or 7 (with seconds/optional year). Any other count bails with the trimmed expression and the actual field count. The normalized expression is then parsed by the `cron` crate.

Solutions

  1. Count the fields in your expression; make it 5 fields (min hour dom mon dow) for standard cron.
  2. Add seconds explicitly as the first field if you need sub-minute precision (6 fields), or seconds + year (7 fields).
  3. Replace `@daily`/`@hourly` descriptors with their explicit 5-field equivalents (`0 0 * * *`, `0 * * * *`).
  4. Quote or escape any field content containing spaces so it isn't split into extra fields.

Example fix

// before
validate_schedule_cron_expr("0 12 * *")?; // 4 fields

// after
validate_schedule_cron_expr("0 12 * * *")?; // 5 fields
Defensive patterns

Strategy: validation

Validate before calling

// Count cron fields before validating
fn cron_field_count(expr: &str) -> usize {
    expr.trim().split_whitespace().count()
}
assert!((5..=7).contains(&cron_field_count(expr)));

Type guard

fn is_valid_cron_field_count(expr: &str) -> bool {
    matches!(expr.trim().split_whitespace().count(), 5 | 6 | 7)
}

Try / catch

match validate_schedule_cron_expr(expr) {
    Err(e) if e.to_string().contains("expected 5, 6, or 7 fields") => {
        eprintln!("Fix cron fields in: {expr}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Entering a 4-field cron (`0 12 * * *` style with a dropped field), a 3-field shorthand (`daily`-style ranges), or an expression where spaces inside a field (e.g. an unquoted `* * * * * * * *`) inflate the count.

Common situations: Copy-pasting a cron from a tool that uses a different field count (some schedulers use 6-field with seconds, others 5); hand-editing a cron and dropping a field; pasting human text like `every day at noon` or `@daily` descriptors that aren't field-based cron.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at ecc2/src/main.rs:5970

}

fn shell_quote_double(value: &str) -> String {
    format!(
        "\"{}\"",
        value
            .replace('\\', "\\\\")
            .replace('"', "\\\"")
            .replace('\n', "\\n")
    )
}

fn validate_schedule_cron_expr(expr: &str) -> Result<()> {
    let trimmed = expr.trim();
    let normalized = match trimmed.split_whitespace().count() {
        5 => format!("0 {trimmed}"),
        6 | 7 => trimmed.to_string(),
        fields => {
            anyhow::bail!(
                "invalid cron expression `{trimmed}`: expected 5, 6, or 7 fields but found {fields}"
            )
        }
    };
    <cron::Schedule as std::str::FromStr>::from_str(&normalized)
        .with_context(|| format!("invalid cron expression `{trimmed}`"))?;
    Ok(())
}

fn build_legacy_schedule_add_command(draft: &LegacyScheduleDraft) -> Option<String> {
    let cron_expr = draft.cron_expr.as_deref()?;
    let task = draft.task.as_deref()?;
    let mut parts = vec![
        "ecc schedule add".to_string(),
        format!("--cron {}", shell_quote_double(cron_expr)),
        format!("--task {}", shell_quote_double(task)),
    ];
    if let Some(agent) = draft.agent.as_deref() {

View on GitHub (pinned to 8321021c54)