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
- Use a valid IANA zone name, e.g. "Europe/Oslo", "America/New_York", or "UTC".
- In minimal containers, install tzdata (e.g. `apk add tzdata`) or use a Hugo binary/image that embeds it.
- 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
- Use IANA tz database names (America/New_York), not abbreviations or UTC offsets
- Ensure the tzdata is available in minimal containers (install tzdata or import time/tzdata)
- Test config on the CI image, where zone databases may differ from dev machines
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
- failed to decode languages config: %w
- failed to create config: %w
- invalid language configuration for %q
- failed to decode config for language %q: %w
- language name cannot be empty
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/42b005b52bb6407d.json.
Report an issue: GitHub ↗.