gohugoio/hugo · error

invalid timeZone for language %q: %w

Error message

invalid timeZone for language %q: %w

What it means

Raised by Language.loadLocation (langs/language.go:183) when Go's time.LoadLocation cannot resolve the configured timeZone string for a language. Hugo loads a *time.Location per language to localize dates in templates and front matter; an unknown IANA zone name (or a system missing tzdata) makes that impossible, so config compilation fails with the language identified.

Source

Thrown at langs/language.go:183

}

// Deprecated: Use Label instead.
func (l *Language) LanguageName() string {
	hugo.DeprecateWithLogger(".Language.LanguageName", "Use .Language.Label instead.", "v0.158.0", l.Logger())
	return l.Label()
}

func (l *Language) Label() string {
	if l.LanguageConfig.Label != "" {
		return l.LanguageConfig.Label
	}
	return l.LanguageConfig.LanguageName
}

func (l *Language) loadLocation(tzStr string) error {
	location, err := time.LoadLocation(tzStr)
	if err != nil {
		return fmt.Errorf("invalid timeZone for language %q: %w", l.Lang, err)
	}
	l.location = location

	return nil
}

func (l *Language) String() string {
	return l.Lang
}

// Languages is a sortable list of languages.
type Languages []*Language

func (l Languages) AsSet() map[string]bool {
	m := make(map[string]bool)
	for _, lang := range l {
		m[lang.Lang] = true
	}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Use a valid IANA zone name, e.g. "Europe/Oslo", "America/New_York", or "UTC".
  2. In minimal containers, install tzdata (e.g. `apk add tzdata`) or use a Hugo binary/image that embeds it.
  3. Check for per-language timeZone overrides in the languages block, not just the root setting.

Example fix

# before
[languages.fr]
timeZone = "CEST"
# after
[languages.fr]
timeZone = "Europe/Paris"
Defensive patterns

Strategy: validation

Validate before calling

// Validate timeZone values are IANA names before load
for lang, v := range cfg.GetStringMap("languages") {
    if m, ok := v.(map[string]any); ok {
        if tz, ok := m["timeZone"].(string); ok && tz != "" {
            if _, err := time.LoadLocation(tz); err != nil {
                return fmt.Errorf("languages.%s.timeZone %q invalid: %w", lang, tz, err)
            }
        }
    }
}

Type guard

func isValidTimeZone(tz string) bool {
    _, err := time.LoadLocation(tz)
    return err == nil
}

Try / catch

if err != nil && strings.Contains(err.Error(), "invalid timeZone") {
    return fmt.Errorf("use an IANA zone name like \"Europe/Oslo\", not an abbreviation like \"CET\": %w", err)
}

Prevention

When it happens

Trigger: Setting `timeZone` (root or `[languages.<lang>] timeZone`) to a value time.LoadLocation rejects — a misspelled or non-IANA name like "CEST", "PST" (abbreviations), "Europe/Olso", or any zone on a minimal system without a tz database.

Common situations: Using timezone abbreviations or Windows zone names instead of IANA names, typos in Area/City strings, and Docker/scratch/alpine images lacking the tzdata package so even valid names fail to load.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/42b005b52bb6407d.json. Report an issue: GitHub ↗.