{"record":{"id":"0d2837cc55e6862d","repo":"temporalio/temporal","slug":"invalid-calendar-spec-errs","errorCode":null,"errorMessage":"invalid calendar spec: ${errs}","messagePattern":"invalid calendar spec: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/worker/scheduler/spec.go","lineNumber":250,"sourceCode":"\t\t\t\terrs = append(errs, fmt.Sprintf(\"%s has invalid Step\", field))\n\t\t\t}\n\t\t}\n\t}\n\n\tcheckRanges(scs.Second, \"Second\", 0, 59)\n\tcheckRanges(scs.Minute, \"Minute\", 0, 59)\n\tcheckRanges(scs.Hour, \"Hour\", 0, 23)\n\tcheckRanges(scs.DayOfMonth, \"DayOfMonth\", 1, 31)\n\tcheckRanges(scs.Month, \"Month\", 1, 12)\n\tcheckRanges(scs.Year, \"Year\", minCalendarYear, maxCalendarYear)\n\tcheckRanges(scs.DayOfWeek, \"DayOfWeek\", 0, 6)\n\n\tif len(scs.Comment) > maxCommentLen {\n\t\terrs = append(errs, \"comment is too long\")\n\t}\n\n\tif len(errs) > 0 {\n\t\treturn errors.New(\"invalid calendar spec: \" + strings.Join(errs, \", \"))\n\t}\n\treturn nil\n}\n\nfunc validateInterval(i *schedulepb.IntervalSpec) error {\n\tif i == nil {\n\t\treturn errors.New(\"interval is nil\")\n\t}\n\t// TODO: use timestamp.ValidateAndCapProtoDuration after switching to state machine based implementation.\n\t// \tNot adding it to workflow based implementation to avoid potential non-determinism errors.\n\tiv, phase := timestamp.DurationValue(i.Interval), timestamp.DurationValue(i.Phase)\n\tif iv < time.Second {\n\t\treturn errors.New(\"interval is too small\")\n\t} else if phase < 0 {\n\t\treturn errors.New(\"phase is negative\")\n\t} else if phase >= iv {\n\t\treturn errors.New(\"phase cannot be greater than Interval\")\n\t}","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/scheduler/spec.go#L232-L268","documentation":"validateStructuredCalendar collects all validation failures for a schedulepb.CalendarSpec (required fields, oversized comments, out-of-range second/minute/hour values, etc.) and joins them into a single message. This error means the submitted calendar spec structurally failed one or more of those checks and was rejected before the schedule could be compiled or canonicalized.","triggerScenarios":"Calling mustCompileCalendarSpec or canonicalizeSpec with a *schedulepb.CalendarSpec that has invalid or missing field values — e.g. second=61, missing required field, or a Comment longer than maxCommentLen.","commonSituations":"Building calendar specs by hand in Go without using the high-level ScheduleSpec helpers; migrating specs from cron strings where ranges were mis-translated; UI forms that don't clamp minute/hour inputs; long operator notes stuffed into Comment.","solutions":["Read the joined field list in the error message and fix each listed field (e.g. seconds 0-59, minutes 0-59, hours 0-23).","Shorten the Comment field to under maxCommentLen.","Construct specs via the scheduler's high-level ScheduleSpec/calendar helpers instead of raw protobuf structs so defaults are applied.","Validate spec fields client-side (ranges, required fields) before submitting the UpdateSchedule request."],"exampleFix":"// before\nspec := &schedulepb.CalendarSpec{Second: \"61\", Comment: strings.Repeat(\"x\", 600)}\n// after\nspec := &schedulepb.CalendarSpec{Second: \"0\", Minute: \"*/15\", Hour: \"*\", Comment: \"every 15 min\"}","handlingStrategy":"validation","validationCode":"func validCalendar(scs *schedulepb.CalendarSpec) error {\n    var errs []string\n    if n, err := strconv.Atoi(scs.GetSecond()); err != nil || n < 0 || n > 59 { errs = append(errs, \"second out of range\") }\n    if n, err := strconv.Atoi(scs.GetMinute()); err != nil || n < 0 || n > 59 { errs = append(errs, \"minute out of range\") }\n    if n, err := strconv.Atoi(scs.GetHour()); err != nil || n < 0 || n > 23 { errs = append(errs, \"hour out of range\") }\n    if len(scs.GetComment()) > 256 { errs = append(errs, \"comment too long\") }\n    if len(errs) > 0 { return fmt.Errorf(\"invalid calendar spec: %s\", strings.Join(errs, \", \")) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build specs via high-level ScheduleSpec helpers, not raw protobuf structs","Clamp/range-check user-entered time fields in forms and CLIs","Keep the Comment field short (it is metadata, not a log)","Validate specs in unit tests before deploying schedule-creating code"],"tags":["go","scheduler","validation","calendar-spec"],"backgroundTag":"schema-validation-failed","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}