gohugoio/hugo · error
failed convert config to map: %s
Error message
failed convert config to map: %s
What it means
Thrown by output.DecodeConfig (output/config.go:47) when hmaps.ToStringMapE(in) fails to convert the 'outputFormats' configuration value into a map[string]any. The %s inserts the cast error. Hugo expects the [outputFormats] section to be a map keyed by format name; this error means the top-level value is an array, a scalar, or otherwise not a map.
Source
Thrown at output/config.go:47
type OutputFormatConfig struct {
// The MediaType string. This must be a configured media type.
MediaType string
Format
}
var defaultOutputFormat = Format{
BaseName: "index",
Rel: "alternate",
}
func DecodeConfig(mediaTypes media.Types, in any) (*config.ConfigNamespace[map[string]OutputFormatConfig, Formats], error) {
buildConfig := func(in any) (Formats, any, error) {
f := make(Formats, len(DefaultFormats))
copy(f, DefaultFormats)
if in != nil {
m, err := hmaps.ToStringMapE(in)
if err != nil {
return nil, nil, fmt.Errorf("failed convert config to map: %s", err)
}
m = hmaps.CleanConfigStringMap(m)
for k, v := range m {
found := false
for i, vv := range f {
// Both are lower case.
if k == vv.Name {
// Merge it with the existing
if err := decode(mediaTypes, v, &f[i]); err != nil {
return f, nil, err
}
found = true
}
}
if found {
continue
}View on GitHub (pinned to 52c9bd7908)
Solutions
- Ensure [outputFormats] in hugo.toml is a table/map: [outputFormats.NAME] with each format as a sub-table, not an inline array.
- In YAML config use outputFormats: { NAME: {...} } rather than outputFormats: [{...}].
- Run hugo config to dump the resolved config and confirm outputFormats is a map.
- Check any --config overrides or theme config mounts for a conflicting non-map definition.
Example fix
# before (array instead of map)
outputFormats = [
{ name = "MYFORMAT", mediaType = "text/html" }
]
# after (map keyed by name)
[outputFormats.MYFORMAT]
mediaType = "text/html"
baseName = "index" Defensive patterns
Strategy: validation
Validate before calling
// Ensure the outputFormats config value is a map before DecodeConfig.
func ensureOutputFormatsMap(in any) error {
if in == nil { return nil }
if _, ok := in.(map[string]any); !ok {
return fmt.Errorf("outputFormats must be a map, got %T", in)
}
return nil
} Type guard
func isConfigMap(in any) bool {
_, ok := in.(map[string]any)
return ok || in == nil
} Try / catch
ns, err := output.DecodeConfig(mediaTypes, raw)
if err != nil {
return fmt.Errorf("invalid outputFormats config: %w", err)
} Prevention
- Author [outputFormats] as TOML tables or YAML mappings, never arrays.
- Run `hugo config` after config edits to catch structural errors.
- Review theme/config overlays for conflicting shapes.
When it happens
Trigger: Defining [outputFormats] as an array (outputFormats = [{name="x"}]) or a scalar in hugo.toml; loading a config via a source that yields a slice instead of a map; a config merge/overlay producing a non-map at that key.
Common situations: Migrating from an older Hugo config syntax that used a different shape; typos in TOML that create an array-of-tables instead of a table; YAML config using a list where a mapping is expected; environment-injected config overrides that replace the map with a scalar.
Related errors
- media type %q not found
- invalid output format configuration; wrong type for media ty
- failed to decode output format configuration: %w
- OutputFormat with key %q not found
- config not set
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/ea5c0bbe4640e033.
Report an issue: GitHub.