robfig/cron · error
step of range should be a positive number
Error message
step of range should be a positive number: %s
What it means
Thrown by getRange in parser.go when a range step parses to 0, e.g. '*/0' or '1-10/0'. A zero step would divide the range infinitely, so the parser rejects it and requires a strictly positive step. Note that strconv.Atoi also accepts '+0'/'00' forms that reach this check rather than the int-parse error.
Solutions
- Ensure the step value is >= 1 before formatting it into the spec string
- Validate interval config values at load time and reject/substitute a sensible default when 0
- If you meant 'never run', don't register the schedule at all instead of using a 0 step
- Wrap cron.Parse at startup so invalid specs surface immediately
Example fix
// before
if interval == 0 { spec = "*/" + fmt.Sprint(interval) /* -> */0 */ }
// after
if interval <= 0 { return errors.New("interval must be positive") }
spec = "*/" + fmt.Sprint(interval) Defensive patterns
Strategy: validation
Validate before calling
func validStep(step int) bool { return step >= 1 }
// reject interval config values of 0 before formatting "*/%d" Try / catch
sched, err := cron.Parse(spec)
if err != nil {
return fmt.Errorf("invalid cron spec %q: %w", spec, err)
} Prevention
- Zero-check any interval/step value sourced from config or flags
- Give config-driven steps a nonzero default
- Never express 'never run' as a 0 step; skip registration instead
When it happens
Trigger: Calling cron.Parse with specs like '0 */0 * * * *', '0 0 0 1-31/0 * *', or a template where the step value came from a variable that was 0 (e.g. an unset interval config defaulting to 0) and was interpolated as 'N/0'.
Common situations: Config-driven interval values where an unset/zero default gets interpolated into the spec; users typing '*/0' expecting 'never run'; JSON/YAML config with numeric 0 interval lacking zero-validation before string building.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- too many slashes
- multiple optionals may not be configured
- parser does not accept descriptors
- expected exactly fields, found
- expected to fields, found
AI-assisted analysis of robfig/cron@bc59245fe1 (2026-09-07).
Data as JSON: /api/errors/672ec47125fe8dae.
Report an issue: GitHub.
Appendix: source
Thrown at parser.go:314
}
if step > 1 {
extra = 0
}
default:
return 0, fmt.Errorf("too many slashes: %s", expr)
}
if start < r.min {
return 0, fmt.Errorf("beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
}
if end > r.max {
return 0, fmt.Errorf("end of range (%d) above maximum (%d): %s", end, r.max, expr)
}
if start > end {
return 0, fmt.Errorf("beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
}
if step == 0 {
return 0, fmt.Errorf("step of range should be a positive number: %s", expr)
}
return getBits(start, end, step) | extra, nil
}
// parseIntOrName returns the (possibly-named) integer contained in expr.
func parseIntOrName(expr string, names map[string]uint) (uint, error) {
if names != nil {
if namedInt, ok := names[strings.ToLower(expr)]; ok {
return namedInt, nil
}
}
return mustParseInt(expr)
}
// mustParseInt parses the given expression as an int or returns an error.
func mustParseInt(expr string) (uint, error) {
num, err := strconv.Atoi(expr)View on GitHub (pinned to bc59245fe1)