{"record":{"id":"01e518818c86b812","repo":"robfig/cron","slug":"beginning-of-range-d-beyond-end-of-range-d","errorCode":null,"errorMessage":"beginning of range (%d) beyond end of range (%d): %s","messagePattern":"beginning of range \\((.+?)\\) beyond end of range \\((.+?)\\): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"parser.go","lineNumber":311,"sourceCode":"\t\t// Special handling: \"N/step\" means \"N-max/step\".\n\t\tif singleDigit {\n\t\t\tend = r.max\n\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","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/robfig/cron/blob/bc59245fe10efaed9d51b56900192527ed733435/parser.go#L293-L329","documentation":"Thrown by getRange in parser.go when a cron field range has start > end (e.g. '50-10'). The parser only accepts ascending ranges; it does not wrap around field boundaries like some cron implementations (e.g. Vixie cron's '23-2' hours). If you need wrap-around behavior, express it as two ascending ranges joined with commas.","triggerScenarios":"Calling cron.Parse with a wrapping range: '0 50-10 * * * *' (minutes 50→10), '0 0 23-2 * * *' (hours wrapping midnight), '0 0 0 * 11-2 *' (months Nov→Feb wrapping the year).","commonSituations":"Assuming cron wrap-around semantics like Unix crontab; describing a recurring overnight window (22:00–06:00) as '22-6'; writing month ranges that cross December.","solutions":["Split the wrapping range into two ascending comma-separated ranges: '22-6' becomes '22-23,0-6'","Reorder the range so start <= end if that matches the intent","Use a step range with '*' plus a filter if the schedule logic needs wrap-around","Handle the wrap in application logic (e.g. two schedules) rather than one spec string"],"exampleFix":"// before\ncron.Parse(\"0 0 22-6 * * *\") // wrap-around not supported\n// after\ncron.Parse(\"0 0 0-6,22-23 * * *\")","handlingStrategy":"validation","validationCode":"func validAscendingRange(start, end int) bool { return start <= end }\n// for wrap-around windows, split: [start,max]+[min,end]","typeGuard":null,"tryCatchPattern":"sched, err := cron.Parse(spec)\nif err != nil {\n\treturn fmt.Errorf(\"invalid cron spec %q: %w\", spec, err)\n}","preventionTips":["Never rely on cron range wrap-around; split '22-6' into '22-23,0-6'","Check start <= end when building ranges from variables","Document wrap-around windows as two comma-separated ranges in code review checklists"],"tags":["cron","parser","range-validation","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"}