gohugoio/hugo · error

failed to decode languages config

Error message

failed to decode languages config: %w

What it means

Specific to the `languages` decoder (alldecoders.go:236). It calls langs.DecodeConfig, which mapstructure-decodes the languages map and then runs LanguagesInternal.init. init validates every language name is a non-empty valid identifier, that the configured defaultContentLanguage exists and is not disabled, and that disabled-language handling is consistent. Any of those produce a wrapped error here.

Solutions

  1. Confirm every `[languages.<key>]` uses a lowercase identifier matching a valid language code.
  2. Ensure `defaultContentLanguage` matches an existing, non-disabled language key.
  3. Remove any language listed in `disableLanguages` that is also the default, or change the default.
  4. Validate each language block's field types (weight is int, disabled is bool, etc.).

Example fix

# before
defaultContentLanguage = "fr"
[languages]
[languages.en]
weight = 1

# after
defaultContentLanguage = "en"
[languages]
[languages.en]
weight = 1
Defensive patterns

Strategy: validation

Validate before calling

# Verify every language key is a lowercase identifier and defaultContentLanguage matches
python3 - <<'PY'
import tomllib,re
cfg=tomllib.loads(open('hugo.toml').read())
langs=(cfg.get('languages') or {})
for k in langs:
    assert re.fullmatch(r'[a-z][a-z0-9-]*',k), f"bad lang key {k!r}"
dcl=cfg.get('defaultContentLanguage')
if dcl: assert dcl in langs, f"defaultContentLanguage {dcl!r} not in languages"
print("languages ok")
PY

Prevention

When it happens

Trigger: A language key that is empty or contains invalid characters (fails paths.ValidateIdentifier); setting `defaultContentLanguage = "fr"` when no `[languages.fr]` exists; marking the default language as `disabled = true`; a mapstructure decode failure because a language field has the wrong type.

Common situations: Renaming a language but forgetting to update defaultContentLanguage; using uppercase or punctuation in a language key; disabling the default language via disableLanguages flag while it remains the default; locale/languageCode mismatch resolved incorrectly.

Understand the failure class

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/3580bb4e31908e5c. Report an issue: GitHub.

Appendix: source

Thrown at config/allconfig/alldecoders.go:252

		},
	},
	"languages": {
		key: "languages",
		decode: func(d decodeWeight, p decodeConfig) error {
			m := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))
			// Root-level locale/languageCode is passed to DecodeConfig so it can
			// be applied to the default content language inside langs.DecodeConfig.
			// They are passed separately so that an explicit per-lang languageCode
			// can override a root-level languageCode (but not a root-level locale).
			rootLocale := p.p.GetString("locale")
			rootLanguageCode := p.p.GetString("languagecode")
			var (
				err                    error
				defaultContentLanguage string
			)
			p.c.Languages, defaultContentLanguage, err = langs.DecodeConfig(p.c.RootConfig.DefaultContentLanguage, rootLocale, rootLanguageCode, p.c.RootConfig.DisableLanguages, m)
			if err != nil {
				return fmt.Errorf("failed to decode languages config: %w", err)
			}
			for k, v := range p.c.Languages.Config.LanguageConfigs {
				if v.Disabled {
					p.c.RootConfig.DisableLanguages = append(p.c.RootConfig.DisableLanguages, k)
				}
			}

			p.c.RootConfig.DisableLanguages = hstrings.UniqueStringsReuse(p.c.RootConfig.DisableLanguages)
			sort.Strings(p.c.RootConfig.DisableLanguages)
			p.c.RootConfig.DefaultContentLanguage = defaultContentLanguage
			return nil
		},
	},
	"versions": {
		key: "versions",
		decode: func(d decodeWeight, p decodeConfig) error {
			var err error
			m := hmaps.CleanConfigStringMap(p.p.GetStringMap(d.key))

View on GitHub (pinned to 52c9bd7908)