{"record":{"id":"2bc9cafc851b92ca","repo":"temporalio/temporal","slug":"cronstring-has-time-zone-but-missing-fields","errorCode":null,"errorMessage":"CronString has time zone but missing fields","messagePattern":"CronString has time zone but missing fields","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/worker/scheduler/calendar.go","lineNumber":251,"sourceCode":"\t\tComment:    cal.Comment,\n\t}\n\tif len(errs) > 0 {\n\t\treturn nil, errors.New(strings.Join(errs, \", \"))\n\t}\n\treturn ss, nil\n}\n\nfunc parseCronString(c string) (*schedulepb.StructuredCalendarSpec, *schedulepb.IntervalSpec, string, error) {\n\tvar tzName string\n\tvar comment string\n\n\tc = strings.TrimSpace(c)\n\n\t// split out timezone\n\tif strings.HasPrefix(c, \"TZ=\") || strings.HasPrefix(c, \"CRON_TZ=\") {\n\t\ttz, rest, found := strings.Cut(c, \" \")\n\t\tif !found {\n\t\t\treturn nil, nil, \"\", errors.New(\"CronString has time zone but missing fields\")\n\t\t}\n\t\tc = rest\n\t\t_, tzName, _ = strings.Cut(tz, \"=\")\n\t}\n\n\t// split out comment\n\tc, comment, _ = strings.Cut(c, \"#\")\n\tc = strings.TrimSpace(c)\n\tcomment = strings.TrimSpace(comment)\n\n\t// handle @every intervals\n\tif strings.HasPrefix(c, \"@every\") {\n\t\tiv, err := parseCronStringInterval(c)\n\t\treturn nil, iv, \"\", err\n\t}\n\n\t// handle @hourly, etc.\n\tc = handlePredefinedCronStrings(c)","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/scheduler/calendar.go#L233-L269","documentation":"parseCronString supports an optional leading TZ= or CRON_TZ= prefix for cron strings. If the string begins with such a prefix but contains no space-separated fields after it (strings.Cut finds no space), there is no cron expression left to parse and this error is returned.","triggerScenarios":"Passing a schedule/cron string like \"TZ=America/New_York\" or \"CRON_TZ=UTC\" with no trailing cron fields to a Schedule spec or canonicalizeSpec.","commonSituations":"Config value truncated by quoting/whitespace stripping in YAML/env; template rendering that dropped the cron expression; hand-edited schedule JSON where the expression part was accidentally deleted.","solutions":["Append the full 5-7 field cron expression after the timezone prefix, e.g. \"TZ=America/New_York 0 9 * * *\".","Check the source config for truncation — quotes, newlines, or templating that swallowed the rest of the string.","If the schedule doesn't need a custom zone, drop the TZ prefix entirely and rely on UTC/default.","Validate the string by running it through parseCronString (or a cron linter) before persisting the schedule."],"exampleFix":"// before\ncronSpec := \"CRON_TZ=Europe/Berlin\"\n// after\ncronSpec := \"CRON_TZ=Europe/Berlin 30 2 * * *\"","handlingStrategy":"validation","validationCode":"func validateTZCron(c string) error {\n\tc = strings.TrimSpace(c)\n\tif (strings.HasPrefix(c, \"TZ=\") || strings.HasPrefix(c, \"CRON_TZ=\")) && !strings.Contains(c, \" \") {\n\t\treturn errors.New(\"timezone prefix present but no cron fields\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"CronString has time zone but missing fields\") {\n\t// inspect config source for truncation, then resubmit full expression\n}","preventionTips":["Always write the full expression on one line: \"TZ=<zone> <5-7 fields>\".","Check quoting and templating in config loaders that can truncate the string.","Validate cron strings programmatically before persisting schedules."],"tags":["scheduler","cron","timezone","validation","go"],"backgroundTag":"malformed-cron-expression","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}