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
- Count the fields in your expression; make it 5 fields (min hour dom mon dow) for standard cron.
- Add seconds explicitly as the first field if you need sub-minute precision (6 fields), or seconds + year (7 fields).
- Replace `@daily`/`@hourly` descriptors with their explicit 5-field equivalents (`0 0 * * *`, `0 * * * *`).
- 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
- Use a cron-builder library or UI picker rather than hand-writing expressions.
- Expand @-descriptors (@daily, @hourly) to explicit 5-field cron before storing.
- Unit-test stored schedule expressions at config load time.
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
- candidate configuration exceeds 1 MiB
- cron expression ` ` did not yield a future run time
- exactly one candidate-keyed health assertion is required
- harness health evidence exceeds integrity verification bound
- harness health evidence is inconsistent with audit outcome
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)