gohugoio/hugo · error

failed to decode build config in front matter: %s%s

Error message

failed to decode build config in front matter: %s%s

What it means

Hugo failed to decode the `build` (or legacy `_build`) front matter key into its pagemeta.BuildConfig struct (fields like render, list, publishResources). Since Hugo 0.123.0 `build` is a reserved front matter keyword, so any value that isn't a valid build-options map fails decoding. The extra message detail is appended only for the new `build` keyword to warn users who used `build` as a personal param.

Source

Thrown at hugolib/page__meta.go:671

	} else {
		buildConfig = pcfg.Params["build"]
		isNewBuildKeyword = true
	}
	pm.pageConfig.Build, err = pagemeta.DecodeBuildConfig(buildConfig)
	if err != nil {
		var msgDetail string
		if isNewBuildKeyword {
			msgDetail = `. We renamed the _build keyword to build in Hugo 0.123.0. We recommend putting user defined params in the params section, e.g.:
---
title: "My Title"
params:
  build: "My Build"
---
´

`
		}
		return fmt.Errorf("failed to decode build config in front matter: %s%s", err, msgDetail)
	}

	var draft, published, isCJKLanguage *bool
	var userParams map[string]any
	for k, v := range pcfg.Params {
		loki := strings.ToLower(k)

		if loki == "params" {
			vv, err := hmaps.ToParamsAndPrepare(v)
			if err != nil {
				return fmt.Errorf("front matter field %q must be a map: %w", k, err)
			}
			userParams = vv
			delete(pcfg.Params, k)
			continue
		}

		if loki == "published" { // Intentionally undocumented

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. If `build` was your own custom param, move it under the `params:` section of front matter (`params:\n build: ...`) and access it via .Params.build.
  2. If you intend Hugo build options, make it a map with valid keys/values: `build:\n render: never\n list: local\n publishResources: false`.
  3. Migrate any remaining `_build` keys to `build` (the old key is deprecated since 0.145.0).

Example fix

# before
---
title: "My Title"
build: "My Build"
---
# after
---
title: "My Title"
params:
  build: "My Build"
---
Defensive patterns

Strategy: validation

Validate before calling

// Validate front matter 'build' before creating the page
if b, ok := fm["build"]; ok {
    if _, ok := b.(map[string]any); !ok {
        return fmt.Errorf("build must be a map, got %T", b)
    }
}

Type guard

func isMap(v any) bool {
    _, ok := v.(map[string]any)
    return ok
}

Try / catch

if err := site.Build(); err != nil {
    if strings.Contains(err.Error(), "failed to decode build config") {
        // report offending page's front matter to the author
    }
    return err
}

Prevention

When it happens

Trigger: A page's front matter contains `build:` (or deprecated `_build:`) with a value that pagemeta.DecodeBuildConfig cannot map — e.g. a string (`build: "My Build"`), a list, or a map with wrongly-typed fields such as `render: 5` instead of one of never/always/link.

Common situations: Most common after upgrading past Hugo 0.123.0: sites that used `build` as a user-defined param (e.g. a build number or CI tag) at the top level of front matter suddenly break, because `_build` was renamed to `build` and now collides. Also typos inside legitimate build option maps.

Related errors


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