tinyhumansai/openhuman · error

Invalid cron expression: {expression} (expected 5, 6, or 7 f

Error message

Invalid cron expression: {expression} (expected 5, 6, or 7 fields, got {field_count})

What it means

normalize_expression counts whitespace-separated fields: 5 fields (standard crontab: minute hour day month weekday) are accepted and auto-prefixed with a seconds field '0'; 6 (with seconds) or 7 (seconds + year) are crate-native and used verbatim. Any other count is rejected as malformed before the cron parser ever sees it.

Source

Thrown at src/openhuman/cron/schedule.rs:187

        if self.start <= self.end {
            time >= self.start && time <= self.end
        } else {
            // Window spans midnight (e.g. 22:00 to 06:00).
            time >= self.start || time <= self.end
        }
    }
}

pub fn normalize_expression(expression: &str) -> Result<String> {
    let expression = expression.trim();
    let field_count = expression.split_whitespace().count();

    match field_count {
        // standard crontab syntax: minute hour day month weekday
        5 => Ok(format!("0 {expression}")),
        // crate-native syntax includes seconds (+ optional year)
        6 | 7 => Ok(expression.to_string()),
        _ => anyhow::bail!(
            "Invalid cron expression: {expression} (expected 5, 6, or 7 fields, got {field_count})"
        ),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::TimeZone;

    #[test]
    fn next_run_for_schedule_supports_every_and_at() {
        let now = Utc::now();
        let every = Schedule::Every { every_ms: 60_000 };
        let next = next_run_for_schedule(&every, now).unwrap();
        assert!(next > now);

        let at = now + ChronoDuration::minutes(10);

View on GitHub (pinned to 7491200858)

Solutions

  1. Count your fields: write exactly 5 (standard) or 6/7 (seconds, optional year) whitespace-separated fields
  2. Strip any command/argument tail — the command lives in the job's separate command/prompt field
  3. Prefer the 5-field form; the core prepends the seconds field automatically

Example fix

# before (command pasted into the expression)
"*/5 * * * * /usr/bin/backup"

# after
"*/5 * * * *"  # command goes in the job's command/prompt field
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

function isValidCronExpression(expr: string): boolean {
  const fields = expr.trim().split(/\s+/).length;
  return fields >= 5 && fields <= 7;
}

Prevention

When it happens

Trigger: Submitting '*/5 * * *' (4 fields, weekday missing), an 8-field expression, or a full crontab line with its command tail pasted in ('*/5 * * * * /usr/bin/backup' — 6 fields, the 6th being garbage downstream). Leading/trailing/multiple spaces are fine (trim + split_whitespace).

Common situations: Hand-writing cron and dropping a field; copying a whole crontab line including the command; adding seconds to a 5-field expression creating an unintended reading; expecting @daily-style shorthands to work (they are just words here).

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/e9db854bba6fecbc. Report an issue: GitHub.