{"record":{"id":"672ec47125fe8dae","repo":"robfig/cron","slug":"step-of-range-should-be-a-positive-number-s","errorCode":null,"errorMessage":"step of range should be a positive number: %s","messagePattern":"step of range should be a positive number: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"parser.go","lineNumber":314,"sourceCode":"\t\t}\n\t\tif step > 1 {\n\t\t\textra = 0\n\t\t}\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"too many slashes: %s\", expr)\n\t}\n\n\tif start < r.min {\n\t\treturn 0, fmt.Errorf(\"beginning of range (%d) below minimum (%d): %s\", start, r.min, expr)\n\t}\n\tif end > r.max {\n\t\treturn 0, fmt.Errorf(\"end of range (%d) above maximum (%d): %s\", end, r.max, expr)\n\t}\n\tif start > end {\n\t\treturn 0, fmt.Errorf(\"beginning of range (%d) beyond end of range (%d): %s\", start, end, expr)\n\t}\n\tif step == 0 {\n\t\treturn 0, fmt.Errorf(\"step of range should be a positive number: %s\", expr)\n\t}\n\n\treturn getBits(start, end, step) | extra, nil\n}\n\n// parseIntOrName returns the (possibly-named) integer contained in expr.\nfunc parseIntOrName(expr string, names map[string]uint) (uint, error) {\n\tif names != nil {\n\t\tif namedInt, ok := names[strings.ToLower(expr)]; ok {\n\t\t\treturn namedInt, nil\n\t\t}\n\t}\n\treturn mustParseInt(expr)\n}\n\n// mustParseInt parses the given expression as an int or returns an error.\nfunc mustParseInt(expr string) (uint, error) {\n\tnum, err := strconv.Atoi(expr)","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/robfig/cron/blob/bc59245fe10efaed9d51b56900192527ed733435/parser.go#L296-L332","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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"],"exampleFix":"// before\nif interval == 0 { spec = \"*/\" + fmt.Sprint(interval) /* -> */0 */ }\n// after\nif interval <= 0 { return errors.New(\"interval must be positive\") }\nspec = \"*/\" + fmt.Sprint(interval)","handlingStrategy":"validation","validationCode":"func validStep(step int) bool { return step >= 1 }\n// reject interval config values of 0 before formatting \"*/%d\"","typeGuard":null,"tryCatchPattern":"sched, err := cron.Parse(spec)\nif err != nil {\n\treturn fmt.Errorf(\"invalid cron spec %q: %w\", spec, err)\n}","preventionTips":["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"],"tags":["cron","parser","step","go"],"backgroundTag":"invalid-argument-value","analyzedSha":"bc59245fe10efaed9d51b56900192527ed733435","analyzedAt":"2026-09-07T00:35:06.760Z","contentChangedAt":"2026-09-07T00:35:06.760Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}