gohugoio/hugo · error

%q is not a valid configuration format

Error message

%q is not a valid configuration format

What it means

Decoder.UnmarshalFileToMap derives the data format from the filename's extension via FormatFromString; if the extension doesn't map to a known format (toml, yaml/yml, json, xml, csv, org), it returns this error rather than guessing. Hugo refuses to parse configuration/data files whose format it cannot identify.

Source

Thrown at parser/metadecoders/decoder.go:106

	if m == nil {
		// We migrated to github.com/goccy/go-yaml in v0.152.0,
		// which produces nil maps for empty YAML files (and empty map nodes), unlike gopkg.in/yaml.v2.
		//
		// To prevent crashes when trying to handle empty config files etc., we ensure we always return a non-nil map here.
		// See issue 14074.
		m = make(map[string]any)
	}

	return m, err
}

// UnmarshalFileToMap is the same as UnmarshalToMap, but reads the data from
// the given filename.
func (d Decoder) UnmarshalFileToMap(fs afero.Fs, filename string) (map[string]any, error) {
	format := FormatFromString(filename)
	if format == "" {
		return nil, fmt.Errorf("%q is not a valid configuration format", filename)
	}

	data, err := afero.ReadFile(fs, filename)
	if err != nil {
		return nil, err
	}
	return d.UnmarshalToMap(data, format)
}

// UnmarshalStringTo tries to unmarshal data to a new instance of type typ.
func (d Decoder) UnmarshalStringTo(data string, typ any) (any, error) {
	data = strings.TrimSpace(data)
	// We only check for the possible types in YAML, JSON and TOML.
	switch typ.(type) {
	case string:
		return data, nil
	case map[string]any, hmaps.Params:
		format := d.FormatFromContentString(data)

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Rename the file so its extension matches its actual format: `.toml`, `.yaml`/`.yml`, `.json`, `.xml`, or `.org` (e.g. `hugo.toml`, `config/_default/params.yaml`).
  2. Fix typoed extensions (`.ymal` → `.yaml`, `.jsn` → `.json`).
  3. If the content is in one format but the extension says otherwise, convert the content or the extension so they agree — Hugo dispatches the parser purely on the extension.

Example fix

# before
config/_default/params.ymal

# after
config/_default/params.yaml
Defensive patterns

Strategy: validation

Validate before calling

var supported = map[string]bool{".toml": true, ".yaml": true, ".yml": true, ".json": true, ".xml": true, ".csv": true, ".org": true}
func canDecode(filename string) bool { return supported[strings.ToLower(filepath.Ext(filename))] }

Type guard

func isKnownFormat(f metadecoders.Format) bool { return f != "" } // FormatFromString returns "" for unknown

Try / catch

if err != nil && strings.Contains(err.Error(), "not a valid configuration format") {
    // report the file's extension; rename or convert to toml/yaml/json
}

Prevention

When it happens

Trigger: Passing a filename with an unrecognized or missing extension to UnmarshalFileToMap — e.g. loading a config or theme config named `config.txt`, `hugo.conf`, `config` (no extension), or a data/config file with a typoed extension like `.ymal` or `.jsn`.

Common situations: Renaming `hugo.toml` to something nonstandard; editors saving `config.toml.bak` or `hugo.yaml.txt`; migrating from another SSG whose config file has a different extension; scripts generating config files without extensions.

Related errors


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