AppCrib
Developer Tools

Cron Expression Validator That Tells You What's Wrong

Launch·Published by AppCrib··
LintcronSee exactly which cron field is wrong, and why.

How do I validate a cron expression?

Paste it into Lintcron at appcrib.com/lintcron. Each of the five, six, or seven fields is parsed and rendered as a distinct labeled segment. If a field is invalid, that segment turns red and an inline error names the field, the offending value, and the rule it breaks. If the expression is valid, you get a plain-English description and the next five UTC run times. No sign-up. No backend. No flipping between three different sites to figure out which field is the problem.

That last part is the whole point. Crontab.guru handles roughly 4 million visits a month and has been the bookmark of record for a decade, but it has a blind spot that catches every backend and DevOps engineer sooner or later. When you type something invalid, it just goes quiet. No error, no red underline, no "hour 25 is out of range." You stare at five fields and guess. Lintcron exists because that guessing game is the most common cron frustration developers have, and nothing on the web has fixed it.

Why does crontab.guru not show error messages?

Crontab.guru was built as a parser, not a linter. It evolved into a reference tool: if your expression parses, you get a description and a next-run preview. If it doesn't parse, the UI falls silent and lets you figure out the rest. That worked fine when most developers only touched five-field Unix cron a few times a year. It holds up less well now that the same engineer might be writing a Kubernetes CronJob schedule on Monday, a GitHub Actions trigger on Tuesday, and a Quartz expression for a Spring job on Wednesday, each with different rules about seconds, years, day-of-week aliases, and the ? character.

Lintcron runs cron-validate on every keystroke with a 150ms debounce, and cron-validate returns a structured error array instead of a single boolean. Each error is attached to a specific field, so the UI can paint the field that failed and print the rule that was violated. Nothing to bookmark, nothing to learn. If you typed 0 25 * * *, the hour segment turns red and a line under the input reads "Hour field: 25 exceeds maximum of 23." That is the entire pitch.

What's the difference between Unix, Quartz, and AWS EventBridge cron syntax?

Short version: field count, allowed characters, and what each field means.

  • Unix / POSIX cron uses five fields in the order minute, hour, day-of-month, month, day-of-week. No seconds. No years. Zero means Sunday for day-of-week (sometimes seven does too). Standard on Linux servers, supported everywhere from /etc/crontab to most job schedulers.
  • Cron with seconds adds a sixth field to the front for seconds. Some platforms support this flavor (Spring's @Scheduled, Node-cron, a few others). Others reject it outright.
  • Quartz uses six or seven fields: seconds, minutes, hours, day-of-month, month, day-of-week, and an optional year. Quartz also requires a ? character in one of the two day fields, because it refuses to let you specify both. It supports L (last), W (nearest weekday), and # (nth weekday of the month). If you paste a Quartz expression into a Unix validator, you get nonsense.
  • AWS EventBridge uses a six-field variant with the year field at the end and the Quartz-style ? character required for whichever day field you aren't using. It does not accept 0 for seconds the way Quartz does, it has its own rules about month aliases, and it is UTC-only.
  • GitHub Actions uses five-field Unix cron with POSIX syntax, but scheduled workflows run at a minimum five-minute granularity in UTC and queue rather than fire on the exact minute you specified. Valid syntax, surprising behavior.
  • Kubernetes CronJob uses five-field Unix cron with an optional timeZone field on the CronJob spec. No seconds, no years, no ?. The quirk here isn't syntax. It's that concurrencyPolicy and startingDeadlineSeconds change when jobs actually run.

Lintcron's Format Detection badge looks at the field count and the presence of Quartz-specific characters and tells you which flavor it thinks you have. If the detected format disagrees with the platform you're targeting, that is exactly the moment silent confusion would otherwise set in.

How do I know which field in my cron expression is wrong?

Look for the red segment. That is the whole user interface for this question.

Each cron expression in Lintcron is rendered as a row of labeled chips: minute, hour, day-of-month, month, day-of-week, optionally seconds and year. Valid chips stay in the neutral surface color. Invalid chips turn red, and the inline error panel below names the field and the rule it broke. Multiple invalid fields show multiple messages simultaneously, so if your expression has three problems you see three problems, not just the first one the parser bailed on.

Once you fix a field, the red highlight drops within one 150ms debounce cycle. If you break another field while fixing the first, the highlight moves. It is the kind of feedback loop that takes the "parse the cron output in my head" step out of the process entirely.

Does GitHub Actions support 6-field cron expressions with seconds?

No. GitHub Actions' scheduled workflows use standard five-field POSIX cron, run in UTC, and round to a five-minute minimum resolution. There is no seconds field. There is no year field. Schedules are best-effort. GitHub has publicly acknowledged that scheduled workflows can be delayed or dropped during periods of high load, especially at the top of the hour. If you need precise scheduling, a self-hosted runner with a systemd timer, or a platform with stronger SLAs, is the honest recommendation.

When you paste a five-field expression into Lintcron, the Format Detection badge reads "Unix (5-field)" and the validator applies POSIX rules. When you paste a six-field expression, the badge switches to "With Seconds (6-field)" and the rules shift. Neither of those is a GitHub Actions-specific mode yet (that's a v1.1 opportunity), but the format detection alone catches the most common mistake: writing a Spring-style six-field expression and pasting it into a GitHub Actions workflow file.

How do I write a Kubernetes CronJob schedule?

Use five-field Unix cron in the spec.schedule field of your CronJob manifest. A schedule that runs every weekday at 9:00 UTC looks like this:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: weekday-report
spec:
  schedule: "0 9 * * 1-5"
  timeZone: "America/New_York"  # optional, Kubernetes 1.27+
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: report
              image: my-reporter:latest
          restartPolicy: OnFailure

Paste the schedule value into Lintcron and you get "At 9:00 AM, Monday through Friday" as the description, plus the next five UTC firings in ISO-8601. That gives you a second pair of eyes before kubectl apply, which matters specifically because a wrong cron schedule in Kubernetes fails silently. The CronJob is created, the job just never fires, and the first notice you get is the Slack message asking why Monday's report didn't land.

What does the '?' character mean in a Quartz cron expression?

? means "no specific value" and it only makes sense in the day-of-month or day-of-week field. Quartz does not let you specify both day fields at the same time because they conflict, so one of them is required to be ?. If you want a Quartz expression that fires every Monday at 9:00 AM, the day-of-month field becomes ? because the constraint is already fully expressed by the day-of-week field:

0 0 9 ? * MON

If you specified both (0 0 9 1 * MON), Quartz would reject the expression. Lintcron's format detector notices the ? character, flags the expression as Quartz, and applies the right rules. If you tried to use ? in a Unix five-field expression, you would get an inline error, because ? is not legal POSIX cron syntax.

Why is my cron expression firing at the wrong time?

The usual suspects:

  1. Timezone mismatch. Most cron implementations run in UTC unless you explicitly set otherwise. A schedule of 0 9 * * * runs at 9 AM UTC, not 9 AM local. Lintcron shows the next five runs in UTC precisely so this ambiguity is impossible to miss.
  2. Daylight saving time. If your scheduler runs in a local timezone, DST jumps can cause 2 AM schedules to fire twice (fall back) or skip (spring forward). Most managed platforms (AWS, GitHub) sidestep this by staying UTC-only.
  3. Platform resolution. GitHub Actions rounds to five-minute boundaries and can queue. AWS EventBridge has a one-minute minimum. Kubernetes honors the exact minute but may delay by startingDeadlineSeconds under load.
  4. Field confusion. Day-of-week zero means Sunday on most systems. Seven also means Sunday on some. Monday on a few weird ones. Aliases like MON are supported in Quartz and GitHub Actions but not always on bare POSIX cron.
  5. Comma vs range vs step. 1,2,3 is not the same as 1-3 which is not the same as */3. Lintcron's human-readable description catches these. If the output reads "At 1, 2, and 3 minutes" when you meant "every 3 minutes," you caught the bug before it fired.

The honest answer is that cron is a 50-year-old syntax retrofitted onto twelve different modern platforms, and the only reliable way to know an expression does what you think is to run it through a validator that tells you what it parsed. That is the niche Lintcron fills.

What Lintcron does, in one sentence

Lintcron is a single-page, client-side cron expression validator that renders each field as a labeled segment, paints invalid fields red with specific error messages, detects whether your expression is Unix five-field, six-field with seconds, or Quartz seven-field, and shows a plain-English description plus the next five UTC run times. It is free, ad-supported, and has no sign-up. Eight preset buttons cover the common patterns if you want a starting point. A copy button sends the corrected expression to your clipboard.

If you write cron expressions for Kubernetes CronJobs, GitHub Actions workflows, AWS EventBridge rules, or Spring schedules on a regular basis, Lintcron is the tool that exists to make the "which field is broken and why" step take two seconds instead of two minutes. Try it at appcrib.com/lintcron.

Lintcron
See exactly which cron field is wrong, and why.
Try Lintcron