apache/superset · error · ReportScheduleCrontabNotValidError

Invalid crontab schedule: %(cron_schedule)s never matches a

Error message

Invalid crontab schedule: %(cron_schedule)s never matches a valid date

What it means

Raised when croniter(cron_schedule) raises CroniterBadDateError, meaning the crontab expression can never match a valid date. Superset wraps it as ReportScheduleCrontabNotValidError so the API returns an actionable message naming the offending crontab instead of a raw croniter traceback. It is part of crontab validation on report/alert create and update.

Source

Thrown at superset/commands/report/base.py:360

        # Since configuration is in minutes, we only need to validate
        # in case `minimum_interval` is <= 120 (2min)
        if minimum_interval < 120:
            return

        iterations = 60 if minimum_interval <= 3660 else 24
        try:
            schedule = croniter(cron_schedule)
            current_exec = next(schedule)

            for _i in range(iterations):
                next_exec = next(schedule)
                diff, current_exec = next_exec - current_exec, next_exec
                if int(diff) < minimum_interval:
                    raise ReportScheduleFrequencyNotAllowed(
                        report_type=report_type, minimum_interval=minimum_interval
                    )
        except CroniterBadDateError as ex:
            raise ReportScheduleCrontabNotValidError(
                cron_schedule=cron_schedule
            ) from ex

View on GitHub (pinned to f4587218dd)

Solutions

  1. Fix the impossible date: use a real combination like '0 0 31 1,3,5,7,8,10,12 *' (31st only in 31-day months) or '59 23 L * *' style last-day syntax if supported
  2. Pre-validate the expression with croniter before calling the API
  3. If you intended 'last day of month', use a day-of-week/last-day form croniter accepts

Example fix

# before
crontab = '0 0 31 2 *'   # Feb 31 never exists -> CroniterBadDateError

# after
from croniter import croniter
croniter.is_valid('0 0 28 2 *')  # True; use a real date
Defensive patterns

Strategy: validation

Validate before calling

from croniter import croniter

if not croniter.is_valid(crontab):
    raise ValueError(f'Invalid crontab: {crontab!r}')  # catches never-matching dates

Type guard

def is_valid_crontab(expr: str) -> bool:
    return croniter.is_valid(expr)

Try / catch

try:
    CreateReportCommand(user, payload).run()
except ReportScheduleCrontabNotValidError as ex:
    show_error(f'{ex.cron_schedule} never matches a valid date; fix the expression')

Prevention

When it happens

Trigger: Submitting a crontab such as '0 0 31 2 *' (Feb 31) or '0 0 30 2 *' (Feb 30) — dates that never exist — to the report/alert API. Any five-field expression whose day-of-month/month combination is impossible.

Common situations: Hand-written crontabs copied from a spec ('run on the 31st of February'); UI or script generating end-of-month schedules without clamping; typos in the month field.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/59f782e7be4ef82f. Report an issue: GitHub.