gohugoio/hugo · error
failed to unmarshal config for path %q: %w
Error message
failed to unmarshal config for path %q: %w
What it means
Raised while loading the split config directory (`config/_default`, `config/production`, etc.): a config file found during the walk failed to parse via metadecoders.UnmarshalFileToMap. The error wraps the underlying TOML/YAML/JSON syntax error and pins error reporting to the exact file path.
Source
Thrown at config/configLoader.go:172
return nil
}
if fi.IsDir() {
dirnames = append(dirnames, path)
return nil
}
if !IsValidConfigFilename(path) {
return nil
}
name := paths.Filename(filepath.Base(path))
item, err := metadecoders.Default.UnmarshalFileToMap(sourceFs, path)
if err != nil {
// This will be used in error reporting, use the most specific value.
dirnames = []string{path}
return fmt.Errorf("failed to unmarshal config for path %q: %w", path, err)
}
var keyPath []string
var unwrapKey string
if !DefaultConfigNamesSet[name] {
// Can be params.jp, menus.en etc.
name, lang := paths.FileAndExtNoDelimiter(name)
unwrapKey = name
keyPath = []string{name}
if lang != "" {
keyPath = []string{"languages", lang}
switch name {
case "menu", "menus":
keyPath = append(keyPath, "menus")
case "params":
keyPath = append(keyPath, "params")View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Open the file at the quoted path and fix the syntax error described in the wrapped message (it includes line/position for TOML/YAML).
- Ensure the file's content matches its extension — TOML in `.toml`, YAML in `.yaml`.
- Check for leftover git conflict markers or editor artifacts; validate the file with a TOML/YAML linter.
- Move non-config files out of the config directory.
Example fix
# before (config/_default/params.toml) [social twitter = "user" # after [social] twitter = "user"
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that the value at the path is a table/map before decoding into a struct
v := cfg.Get("outputFormats")
if v != nil {
if _, ok := v.(maps.Params); !ok {
return fmt.Errorf("config key %q must be a table, got %T", "outputFormats", v)
}
} Type guard
func asParams(v any) (maps.Params, bool) {
p, ok := v.(maps.Params)
return p, ok
} Try / catch
conf, err := allconfig.LoadConfig(configs.ConfigSourceDescriptor{...})
if err != nil {
// "failed to unmarshal config for path %q" names the offending top-level key —
// its TOML/YAML shape (scalar vs table vs array) doesn't match the expected schema
return fmt.Errorf("load config: %w", err)
} Prevention
- The %q path in the error names the config section whose shape is wrong — check whether it should be a table ([section]) vs array of tables ([[section]]) vs scalar
- YAML indentation errors commonly turn a map into a string; lint config files (yamllint/taplo) in CI
- When upgrading Hugo, diff the release notes for config schema changes before assuming your old file still unmarshals
When it happens
Trigger: Any file with a valid config filename/extension under a config dir containing malformed content — TOML with unbalanced brackets or duplicate keys, YAML with bad indentation or tabs, JSON with trailing commas — encountered by `hugo`, `hugo server`, or `hugo config` when merging the config directory.
Common situations: Merge-conflict markers (`<<<<<<<`) left in a config file; editing `config/_default/params.toml` with YAML syntax (or vice versa) so the extension doesn't match the content; smart quotes pasted from docs; stray non-config text files saved with a `.toml`/`.yaml` extension in the config tree.
Related errors
- failed to load config: %w
- failed to load translations: %w%s
- failed to parse file %q: %s
- failed to detect format from content
- invalid Highlight option: %s
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/4bbb04f07cc8de10.json.
Report an issue: GitHub ↗.