temporalio/temporal · error
${errs}
Error message
${errs} What it means
parseCalendarToStructured converts a CalendarSpec into a StructuredCalendarSpec by parsing each field independently; errors from every field are collected and joined with commas into a single error listing all offending fields (e.g. "DayOfMonth: ... out of range, Month: ..."). It fires when any of Second/Minute/Hour/DayOfWeek/DayOfMonth/Month/Year is malformed or out of range.
Source
Thrown at service/worker/scheduler/calendar.go:236
makeRangeOrNil := func(s, field, def string, minVal, maxVal int, parseMode parseMode) []*schedulepb.Range {
r, err := makeRange(s, field, def, minVal, maxVal, parseMode)
if err != nil {
errs = append(errs, err.Error())
}
return r
}
ss := &schedulepb.StructuredCalendarSpec{
Second: makeRangeOrNil(cal.Second, "Second", "0", 0, 59, parseModeInt),
Minute: makeRangeOrNil(cal.Minute, "Minute", "0", 0, 59, parseModeInt),
Hour: makeRangeOrNil(cal.Hour, "Hour", "0", 0, 23, parseModeInt),
DayOfWeek: makeRangeOrNil(cal.DayOfWeek, "DayOfWeek", "*", 0, 7, parseModeDow),
DayOfMonth: makeRangeOrNil(cal.DayOfMonth, "DayOfMonth", "*", 1, 31, parseModeInt),
Month: makeRangeOrNil(cal.Month, "Month", "*", 1, 12, parseModeMonth),
Year: makeRangeOrNil(cal.Year, "Year", "*", minCalendarYear, maxCalendarYear, parseModeYear),
Comment: cal.Comment,
}
if len(errs) > 0 {
return nil, errors.New(strings.Join(errs, ", "))
}
return ss, nil
}
func parseCronString(c string) (*schedulepb.StructuredCalendarSpec, *schedulepb.IntervalSpec, string, error) {
var tzName string
var comment string
c = strings.TrimSpace(c)
// split out timezone
if strings.HasPrefix(c, "TZ=") || strings.HasPrefix(c, "CRON_TZ=") {
tz, rest, found := strings.Cut(c, " ")
if !found {
return nil, nil, "", errors.New("CronString has time zone but missing fields")
}
c = rest
_, tzName, _ = strings.Cut(tz, "=")View on GitHub (pinned to bde624efd1)
Solutions
- Parse the joined message: each comma-separated segment names the failing field; fix each one's value/expression.
- Validate ranges before constructing the spec (Second 0-59, Minute 0-59, Hour 0-23, DayOfMonth 1-31, Month 1-12, DayOfWeek 0-7, Year in supported range).
- Use '*' for fields you don't intend to constrain instead of numeric guesses.
- Test the spec locally with parseCalendarToStructured/mustCompileCalendarSpec or a unit test before applying to production schedules.
Example fix
// before cal.Month = "13" cal.DayOfWeek = "8" // after cal.Month = "1-12" cal.DayOfWeek = "0-6"
Defensive patterns
Strategy: validation
Validate before calling
var fieldBounds = map[string][2]int{
"Second": {0, 59}, "Minute": {0, 59}, "Hour": {0, 23},
"DayOfMonth": {1, 31}, "Month": {1, 12}, "DayOfWeek": {0, 7},
} Try / catch
ss, err := parseCalendarToStructured(cal)
if err != nil {
for _, part := range strings.Split(err.Error(), ", ") {
// each part names one invalid field; fix and retry
}
} Prevention
- Fix each comma-separated field name reported in the error message.
- Use '*' for unconstrained fields instead of guessed numbers.
- Add unit tests compiling calendar specs before production schedule updates.
When it happens
Trigger: Creating a schedule with a CalendarSpec whose fields include invalid values or unparsable expressions (bad ranges, unknown month/day names, values outside each field's bounds).
Common situations: Constructing CalendarSpec protobufs programmatically with uninitialized or wrong-range fields; validating user-supplied cron strings via the scheduler; copies of legacy specs after schema/version changes to field formats.
Related errors
- out of range
- invalid calendar spec: ${errs}
- conflicting timezone names
- CronString has time zone but missing fields
- CronString does not have 5-7 fields
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/6f52da23946d7010.
Report an issue: GitHub.