gohugoio/hugo · error
permalinks: unsupported config type %T
Error message
permalinks: unsupported config type %T
What it means
Hugo's DecodePermalinksConfig accepts either the legacy map-based permalinks format or the newer slice-of-maps format. When the value under the `permalinks` config key is neither a map (map[string]any / Params) nor convertible to []map[string]any via hmaps.ToSliceStringMap, decoding fails with this error, reporting the Go type it received. It fires at config-load time, aborting the build.
Source
Thrown at resources/page/permalinks.go:531
// DecodePermalinksConfig decodes the permalinks configuration.
// It supports both the new slice-based format and the legacy map-based formats.
func DecodePermalinksConfig(in any) (PermalinksConfig, error) {
if in == nil {
return nil, nil
}
switch v := in.(type) {
// Check legacy formats first.
case map[string]any:
return decodePermalinksMap(v)
case hmaps.Params:
return decodePermalinksMap(v)
default:
if ms, err := hmaps.ToSliceStringMap(in); err == nil {
// New slice format.
return decodePermalinksSlice(ms)
}
return nil, fmt.Errorf("permalinks: unsupported config type %T", in)
}
}
func decodePermalinksSlice(ms []map[string]any) (PermalinksConfig, error) {
var configs PermalinksConfig
for _, m := range ms {
m = hmaps.CleanConfigStringMap(m)
var cfg PermalinkConfig
if targetVal, ok := m["target"]; ok {
if err := mapstructure.WeakDecode(targetVal, &cfg.Target); err != nil {
return nil, fmt.Errorf("permalinks: failed to decode target: %w", err)
}
cfg.Target.Kind = strings.ToLower(cfg.Target.Kind)
cfg.Target.Path = filepath.ToSlash(strings.ToLower(cfg.Target.Path))
}
if patternVal, ok := m["pattern"]; ok {View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Make `permalinks` a map of section→pattern, e.g. `[permalinks]\nposts = '/:year/:month/:slug/'`.
- Or use the new slice format: an array of tables each with `pattern` (and optional `target`).
- Check YAML indentation so the value parses as a mapping, not a scalar or string list.
Example fix
# before (hugo.toml) permalinks = "/:year/:slug/" # after [permalinks] posts = "/:year/:slug/"
Defensive patterns
Strategy: type-guard
Validate before calling
// site config: ensure permalinks is a map of string→string or string→map // permalinks: // page: // posts: /:year/:slug/
Type guard
func validPermalinksConfig(v any) bool {
switch m := v.(type) {
case map[string]any:
for _, val := range m {
switch val.(type) {
case string, map[string]any:
default:
return false
}
}
return true
}
return false
} Prevention
- Keep [permalinks] a table of section→string patterns (or kind→table), never arrays or numbers
- Run `hugo config` after editing to confirm the parsed shape
- Quote pattern values in TOML/YAML so they parse as strings
When it happens
Trigger: Setting `permalinks` in hugo.toml/yaml/json to a scalar (string, number, bool) or a plain array of strings instead of a table/map or an array of tables; e.g. `permalinks = 'posts/:year/:slug'` at the top level, or passing a wrong type when composing config programmatically.
Common situations: Typos flattening the config (forgetting the section key so the pattern string sits directly under permalinks); YAML indentation errors turning a mapping into a scalar or list of strings; migrating between the legacy map format and the new slice format and mixing shapes.
Related errors
- failed to compile permalink target %d: %w
- errPermalinkAttributeUnknown
- permalinks: pattern must be a string, got %T
- permalinks: missing pattern
- permalinks configuration not supported for kind %q, supporte
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/2498828ca3102218.json.
Report an issue: GitHub ↗.