{"record":{"id":"d4505e8ebf68d81e","repo":"robfig/cron","slug":"negative-number-d-not-allowed-s","errorCode":null,"errorMessage":"negative number (%d) not allowed: %s","messagePattern":"negative number \\((.+?)\\) not allowed: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"parser.go","lineNumber":337,"sourceCode":"\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)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to parse int from %s: %s\", expr, err)\n\t}\n\tif num < 0 {\n\t\treturn 0, fmt.Errorf(\"negative number (%d) not allowed: %s\", num, expr)\n\t}\n\n\treturn uint(num), nil\n}\n\n// getBits sets all bits in the range [min, max], modulo the given step size.\nfunc getBits(min, max, step uint) uint64 {\n\tvar bits uint64\n\n\t// If step is 1, use shifts.\n\tif step == 1 {\n\t\treturn ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)\n\t}\n\n\t// Else, use a simple loop.\n\tfor i := min; i <= max; i += step {\n\t\tbits |= 1 << i\n\t}","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/robfig/cron/blob/bc59245fe10efaed9d51b56900192527ed733435/parser.go#L319-L355","documentation":"Thrown by mustParseInt in parser.go when a cron field token parses as a negative integer. Cron fields are non-negative by definition (seconds start at 0), so any '-N' token in a position expected to be a plain number is rejected. Note ranges must use '-', e.g. '5-10'; a bare negative like '-5' or '-5-10' hits this error.","triggerScenarios":"Calling cron.Parse with tokens like '0 -5 * * * *', '0 * -10-20 * * *', or a spec built from a signed integer variable (e.g. a negative offset from config) interpolated into the string.","commonSituations":"Passing negative values from config or CLI arguments into spec construction; arithmetic on time values yielding negative offsets that are formatted into the schedule string; confusion between the range separator '-' and a negative sign when concatenating tokens.","solutions":["Clamp or validate numeric inputs to >= 0 before formatting them into the spec","Fix accidental concatenation like start + \"-\" + end when start/end are negative strings","If a negative offset was intended, apply it in code (e.g. subtract duration before scheduling) instead of in the cron spec","Validate spec-bearing config at load time with cron.Parse"],"exampleFix":"// before\nspec := fmt.Sprintf(\"0 %d * * * *\", offset) // offset can be -5\n// after\nif offset < 0 { return errors.New(\"offset must be >= 0\") }\nspec := fmt.Sprintf(\"0 %d * * * *\", offset)","handlingStrategy":"validation","validationCode":"func nonNegative(n int) bool { return n >= 0 }\n// apply to every variable interpolated into a cron spec","typeGuard":null,"tryCatchPattern":"sched, err := cron.Parse(spec)\nif err != nil {\n\treturn fmt.Errorf(\"invalid cron spec %q: %w\", spec, err)\n}","preventionTips":["Clamp signed config values to >= 0 before spec construction","Watch string concatenation: '-' is a range separator, not a minus sign","Prefer formatting validated ints with %d rather than concatenating raw strings"],"tags":["cron","parser","negative-value","go"],"backgroundTag":"value-out-of-range","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"}