hashicorp/nomad · error

Invalid time zone %q: %v

Error message

Invalid time zone %q: %v

What it means

PeriodicConfig.Validate checks that a periodic job's TimeZone field names a loadable IANA time zone via time.LoadLocation. When the zone string is non-empty but cannot be resolved (bad name or missing tz database), the validation error is appended to the job's multierror. The job spec is rejected until the time zone is corrected.

Source

Thrown at nomad/structs/structs.go:5927

}

func (p *PeriodicConfig) Validate() error {
	if !p.Enabled {
		return nil
	}

	var mErr multierror.Error
	if p.Spec != "" && len(p.Specs) != 0 {
		_ = multierror.Append(&mErr, fmt.Errorf("Only cron or crons may be used"))
	}
	if p.Spec == "" && len(p.Specs) == 0 {
		_ = multierror.Append(&mErr, fmt.Errorf("Must specify a spec"))
	}

	// Check if we got a valid time zone
	if p.TimeZone != "" {
		if _, err := time.LoadLocation(p.TimeZone); err != nil {
			_ = multierror.Append(&mErr, fmt.Errorf("Invalid time zone %q: %v", p.TimeZone, err))
		}
	}

	switch p.SpecType {
	case PeriodicSpecCron:
		// Validate the cron spec
		if p.Spec != "" {
			if _, err := cronexpr.Parse(p.Spec); err != nil {
				_ = multierror.Append(&mErr, fmt.Errorf("Invalid cron spec %q: %v", p.Spec, err))
			}
		}
		// Validate the cron specs
		for _, spec := range p.Specs {
			if _, err := cronexpr.Parse(spec); err != nil {
				_ = multierror.Append(&mErr, fmt.Errorf("Invalid cron spec %q: %v", spec, err))
			}
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set TimeZone to a valid IANA zone name, e.g. "America/New_York" or "UTC".
  2. Verify the name with `time.LoadLocation("Zone/Name")` in a quick Go snippet or `tzdata` lookup before submitting.
  3. Ensure the machine running validation has tzdata installed (/usr/share/zoneinfo); in scratch containers embed the tzdata Go package or install tzdata.
  4. Remove the TimeZone field entirely if the default (UTC) is acceptable.

Example fix

// before
periodic {
  cron = "*/5 * * * *"
  time_zone = "EST"
}
// after
periodic {
  cron = "*/5 * * * *"
  time_zone = "America/New_York"
}
Defensive patterns

Strategy: validation

Validate before calling

func validTimeZone(tz string) bool {
    if tz == "" {
        return true
    }
    _, err := time.LoadLocation(tz)
    return err == nil
}
// call before submitting: if !validTimeZone(job.Periodic.TimeZone) { ... }

Prevention

When it happens

Trigger: Submitting/validating a periodic job whose `periodic { time_zone = "..." }` is set to a string that time.LoadLocation cannot resolve, e.g. "EST5EDT" without tzdata, "UTC+2", a typo like "america/new_yorkk", or an empty-named location.

Common situations: Hand-written HCL job files with guessed zone names; using fixed offsets like "+02:00" instead of IANA names; minimal/scratch Docker images lacking /usr/share/zoneinfo so even valid names fail to load.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/f9d628cf096b861e. Report an issue: GitHub.