NousResearch/hermes-agent · error · ValueError

Cron expressions require 'croniter' package. Install with: p

Error message

Cron expressions require 'croniter' package. Install with: pip install croniter

What it means

ValueError raised in parse_schedule: the string was classified as a cron expression (5+ space-separated fields all matching ^[\d*\-,/]+$), but the croniter package needed to validate cron expressions is not installed and could not be auto-ensured by _ensure_croniter(). Interval and ISO-timestamp schedules do not need croniter; only the cron-expression branch does.

Source

Thrown at cron/jobs.py:651

    
    # "every X" pattern → recurring interval
    if schedule_lower.startswith("every "):
        duration_str = schedule[6:].strip()
        minutes = parse_duration(duration_str)
        return {
            "kind": "interval",
            "minutes": minutes,
            "display": f"every {minutes}m"
        }
    
    # Check for cron expression (5 or 6 space-separated fields)
    # Cron fields: minute hour day month weekday [year]
    parts = schedule.split()
    if len(parts) >= 5 and all(
        re.match(r'^[\d\*\-,/]+$', p) for p in parts[:5]
    ):
        if not _ensure_croniter():
            raise ValueError("Cron expressions require 'croniter' package. Install with: pip install croniter")
        # Validate cron expression
        try:
            croniter(schedule)
        except Exception as e:
            raise ValueError(f"Invalid cron expression '{schedule}': {e}")
        return {
            "kind": "cron",
            "expr": schedule,
            "display": schedule
        }
    
    # ISO timestamp (contains T or looks like date)
    if 'T' in schedule or re.match(r'^\d{4}-\d{2}-\d{2}', schedule):
        try:
            # Parse and validate
            dt = datetime.fromisoformat(schedule.replace('Z', '+00:00'))
            # Make naive timestamps timezone-aware at parse time so the stored
            # value doesn't depend on the system timezone matching at check time.

View on GitHub (pinned to c896c09c42)

Solutions

  1. Install croniter into the running interpreter: pip install croniter
  2. If you cannot install, use an equivalent the parser supports without croniter, e.g. an ISO one-shot timestamp — though for recurring schedules croniter is effectively required

Example fix

# before
create_job(schedule="0 9 * * *")
# ValueError: Cron expressions require 'croniter' package.

# after
python -m pip install croniter
create_job(schedule="0 9 * * *")
Defensive patterns

Strategy: fallback

Validate before calling

import importlib.util

def croniter_available() -> bool:
    return importlib.util.find_spec("croniter") is not None

if not croniter_available() and looks_like_cron(expr):
    raise SystemExit("pip install croniter (required for cron expressions)")

Try / catch

try:
    parsed = parse_schedule("0 9 * * *")
except ValueError as e:
    if "croniter" in str(e):
        subprocess.run([sys.executable, "-m", "pip", "install", "croniter"], check=True)
        parsed = parse_schedule("0 9 * * *")
    else:
        raise

Prevention

When it happens

Trigger: create_job(schedule='0 9 * * *') in an environment where croniter is absent (not in requirements, stripped slim install, or a broken import caught by _ensure_croniter).

Common situations: Minimal/slim deployments that excluded the optional croniter dependency; a corrupted venv; croniter removed during an upgrade.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/de7ad20cbff168ba. Report an issue: GitHub.