temporalio/temporal · error
%s End is before Start or not in range [%d-%d]
Error message
%s End is before Start or not in range [%d-%d]
What it means
In makeRange, the end bound of a 'start-end' range expression is parsed with parseValue(rangeParts[1], start, maxVal, ...). If the end value is below start or outside the field's allowed bounds, this error is returned. It conflates two causes: end-before-start and plain out-of-range.
Source
Thrown at service/worker/scheduler/calendar.go:464
start, end := minVal, maxVal
if part != "*" {
if strings.Contains(part, "-") {
// Only a single dash is allowed to denote a range (e.g. "1-5").
// Inputs with multiple dashes like "1-5-7" should raise the
// canonical "too many dashes" error expected by tests.
if strings.Count(part, "-") > 1 { // no negative numbers are expected in spec
return nil, fmt.Errorf("%s has too many dashes", field)
}
rangeParts := strings.SplitN(part, "-", 2)
if len(rangeParts) != 2 {
return nil, fmt.Errorf("%s has too many dashes", field)
}
if start, err = parseValue(rangeParts[0], minVal, maxVal, parseMode); err != nil {
return nil, fmt.Errorf("%s Start is not in range [%d-%d]", field, minVal, maxVal)
}
if end, err = parseValue(rangeParts[1], start, maxVal, parseMode); err != nil {
return nil, fmt.Errorf("%s End is before Start or not in range [%d-%d]", field, minVal, maxVal)
}
} else {
if start, err = parseValue(part, minVal, maxVal, parseMode); err != nil {
return nil, fmt.Errorf("%s is not in range [%d-%d]", field, minVal, maxVal)
}
if !hasStep {
// if / is present, a single value is treated as that value to the
// end. otherwise a single value is just the single value.
end = start
}
}
}
// Special handling for Sunday: Turn "7" into "0", which may require an extra range.
// Consider some cases:
// 0-7 or 1-7 can turn into 0-6
// 3-7 has to turn into 0,3-6
// 3-7/3 can turn into 3-6/3 (7 doesn't match)
// 1-7/2 has to turn into 0,1-6/2View on GitHub (pinned to bde624efd1)
Solutions
- Ensure end >= start within the same range part (use multiple ranges or step expressions instead of wrapping)
- Verify the end bound is within the field's [min-max] range
- Pre-validate schedule strings with the SDK's schedule parser before workflow creation
Example fix
// before Hour: "22-2" // wrapping not supported // after Hour: "22-23" // plus a second spec entry for "0-2"
Defensive patterns
Strategy: validation
Validate before calling
func validCronRangeOrder(part string) error {
p := strings.SplitN(part, "-", 2)
if len(p) != 2 { return nil }
s, err1 := strconv.Atoi(strings.TrimSpace(p[0]))
e, err2 := strconv.Atoi(strings.TrimSpace(p[1]))
if err1 == nil && err2 == nil && e < s {
return fmt.Errorf("range end %d before start %d (wrapping unsupported)", e, s)
}
return nil
} Prevention
- Never write wrapping ranges like '22-2'; split into '22-23' and '0-2' entries
- Validate ranges with the SDK parser in CI before creating schedules
- Use CalendarSpec structured fields instead of raw strings
When it happens
Trigger: Range expressions like '10-5' (end before start), '0-99' on a minutes field, or an invalid end token in a Scheduler calendar spec field.
Common situations: Typos transposing range bounds; assuming wrapping ranges (like '22-2' hours) are supported when they are not; copying ranges across fields with different maxima.
Related errors
- %s Start is not in range [%d-%d]
- %s is not in range [%d-%d]
- out of range
- conflicting timezone names
- ${errs}
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/f0c046ce54b605ad.
Report an issue: GitHub.