robfig/cron · error
negative number ( ) not allowed
Error message
negative number (%d) not allowed: %s
What it means
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.
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
Example fix
// before
spec := fmt.Sprintf("0 %d * * * *", offset) // offset can be -5
// after
if offset < 0 { return errors.New("offset must be >= 0") }
spec := fmt.Sprintf("0 %d * * * *", offset) Defensive patterns
Strategy: validation
Validate before calling
func nonNegative(n int) bool { return n >= 0 }
// apply to every variable interpolated into a cron spec Try / catch
sched, err := cron.Parse(spec)
if err != nil {
return fmt.Errorf("invalid cron spec %q: %w", spec, err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- multiple optionals may not be configured
- parser does not accept descriptors
- expected exactly fields, found
- expected to fields, found
- unknown optional field
AI-assisted analysis of robfig/cron@bc59245fe1 (2026-09-07).
Data as JSON: /api/errors/d4505e8ebf68d81e.
Report an issue: GitHub.
Appendix: source
Thrown at parser.go:337
// 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)
if err != nil {
return 0, fmt.Errorf("failed to parse int from %s: %s", expr, err)
}
if num < 0 {
return 0, fmt.Errorf("negative number (%d) not allowed: %s", num, expr)
}
return uint(num), nil
}
// getBits sets all bits in the range [min, max], modulo the given step size.
func getBits(min, max, step uint) uint64 {
var bits uint64
// If step is 1, use shifts.
if step == 1 {
return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
}
// Else, use a simple loop.
for i := min; i <= max; i += step {
bits |= 1 << i
}View on GitHub (pinned to bc59245fe1)