gohugoio/hugo · error
permalinks: pattern must be a string, got %T
Error message
permalinks: pattern must be a string, got %T
What it means
Thrown by decodePermalinksSlice when a permalink rule has a 'pattern' key but its value is not a string (the type assertion patternVal.(string) fails). Patterns must be strings containing permalink tokens like /:year/:slug/.
Solutions
- Set 'pattern' to a single string value.
- If you need multiple patterns, add separate [[permalinks]] rules instead.
- Double-check quoting in YAML/TOML so the pattern is parsed as a string.
Example fix
# before
[[permalinks]]
target = { path = "/posts/**" }
pattern = ["/:year/:slug/"]
# after
[[permalinks]]
target = { path = "/posts/**" }
pattern = "/:year/:slug/" Defensive patterns
Strategy: type-guard
Validate before calling
if pv, ok := m["pattern"]; ok {
if _, ok := pv.(string); !ok {
return fmt.Errorf("pattern must be string, got %T", pv)
}
} Type guard
func patternIsString(m map[string]any) bool {
v, ok := m["pattern"]
return ok && reflect.TypeOf(v).Kind() == reflect.String
} Try / catch
cfg, err := page.DecodePermalinksConfig(raw)
if err != nil { /* quote pattern / split into multiple rules */ } Prevention
- Always quote pattern values as single strings.
- Use separate [[permalinks]] rules for multiple patterns.
- Validate config quoting in TOML/YAML.
When it happens
Trigger: A list-format permalink rule writes pattern as a number, list, or map, e.g. pattern = ["/:year/:slug/"] (a list) or pattern = 42.
Common situations: Quoting mistakes, YAML list-ifying a single pattern, or JSON config where the pattern value is an array.
Related errors
- permalinks: failed to decode target
- permalinks: unsupported config type %T
- failed to compile permalink target
- failed to decode page map
- permalink attribute not recognised
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/1a62d30630e04a7e.
Report an issue: GitHub.
Appendix: source
Thrown at resources/page/permalinks.go:552
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 {
cfg.Pattern, ok = patternVal.(string)
if !ok {
return nil, fmt.Errorf("permalinks: pattern must be a string, got %T", patternVal)
}
} else {
return nil, fmt.Errorf("permalinks: missing pattern")
}
configs = append(configs, cfg)
}
return configs, nil
}
func decodePermalinksMap(m map[string]any) (PermalinksConfig, error) {
var configs PermalinksConfig
config := hmaps.CleanConfigStringMap(m)
for k, v := range config {
switch v := v.(type) {
case string:View on GitHub (pinned to 52c9bd7908)