temporalio/temporal · error
CronString has time zone but missing fields
Error message
CronString has time zone but missing fields
What it means
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.
Source
Thrown at service/worker/scheduler/calendar.go:251
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, "=")
}
// split out comment
c, comment, _ = strings.Cut(c, "#")
c = strings.TrimSpace(c)
comment = strings.TrimSpace(comment)
// handle @every intervals
if strings.HasPrefix(c, "@every") {
iv, err := parseCronStringInterval(c)
return nil, iv, "", err
}
// handle @hourly, etc.
c = handlePredefinedCronStrings(c)View on GitHub (pinned to bde624efd1)
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.
Example fix
// before cronSpec := "CRON_TZ=Europe/Berlin" // after cronSpec := "CRON_TZ=Europe/Berlin 30 2 * * *"
Defensive patterns
Strategy: validation
Validate before calling
func validateTZCron(c string) error {
c = strings.TrimSpace(c)
if (strings.HasPrefix(c, "TZ=") || strings.HasPrefix(c, "CRON_TZ=")) && !strings.Contains(c, " ") {
return errors.New("timezone prefix present but no cron fields")
}
return nil
} Try / catch
if err != nil && strings.Contains(err.Error(), "CronString has time zone but missing fields") {
// inspect config source for truncation, then resubmit full expression
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- conflicting timezone names
- CronString does not have 5-7 fields
- CronString does not have interval after @every
- %s has too many slashes
- %s missing step value
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/2bc9cafc851b92ca.
Report an issue: GitHub.