gohugoio/hugo · error
failed to convert %T to a string slice
Error message
failed to convert %T to a string slice
What it means
`types.ToStringSlicePreserveStringE` converts a value to `[]string`, wrapping single strings, delegating to `cast.ToStringSliceE`, and finally reflecting over slices/arrays element-by-element. If the value is neither a string nor any slice/array kind (e.g. a map, number, or struct), the reflect fallback hits its default case and returns this error naming the concrete Go type.
Source
Thrown at common/types/convert.go:81
return result, nil
}
// Probably []int or similar. Fall back to reflect.
vv := reflect.ValueOf(v)
switch vv.Kind() {
case reflect.Slice, reflect.Array:
result = make([]string, vv.Len())
for i := range vv.Len() {
s, err := cast.ToStringE(vv.Index(i).Interface())
if err != nil {
return nil, err
}
result[i] = s
}
return result, nil
default:
return nil, fmt.Errorf("failed to convert %T to a string slice", v)
}
}
// TypeToString converts v to a string if it's a valid string type.
// Note that this will not try to convert numeric values etc.,
// use ToString for that.
func TypeToString(v any) (string, bool) {
switch s := v.(type) {
case string:
return s, true
case template.HTML:
return string(s), true
case template.CSS:
return string(s), true
case template.HTMLAttr:
return string(s), true
case template.JS:
return string(s), trueView on GitHub ↗ (pinned to 8a468df065)
Solutions
- Change the value to a string or an array of strings in the config/front matter identified by the printed type (e.g. map[string]interface{} means you wrote a table/map).
- In templates, check the argument you pass — use `slice "a" "b"` or a field that is actually a string list.
- Validate front matter of recently edited content: `hugo --printPathWarnings` and check the file named in the surrounding error context.
Example fix
# before (front matter) tags: name: go # after tags: - go
Defensive patterns
Strategy: type-guard
Validate before calling
if _, ok := v.([]string); !ok {
if _, ok := v.([]any); !ok {
return fmt.Errorf("expected string slice, got %T", v)
}
} Type guard
func toStringSlice(v any) ([]string, bool) {
switch t := v.(type) {
case []string:
return t, true
case []any:
out := make([]string, 0, len(t))
for _, e := range t {
s, ok := e.(string)
if !ok { return nil, false }
out = append(out, s)
}
return out, true
case string:
return []string{t}, true
}
return nil, false
} Prevention
- In config/front matter, write list values as actual arrays, not comma-joined strings or mixed-type lists
- Keep list elements homogeneous strings — a stray number or map in the list breaks conversion
- Normalize scalars to single-element slices at the boundary if callers may pass either
When it happens
Trigger: Config fields or template function arguments that must be a string or list of strings — e.g. taxonomy terms, `keywords`, cascade/permalink lists, `where`/`in` inputs — receiving a map or scalar of the wrong shape; also slices containing elements that can't stringify (the inner cast error propagates).
Common situations: YAML front matter where `tags: foo: bar` (a map) was written instead of `tags: [foo, bar]`; passing a page or dict object where a list of strings is expected in a template; config merging producing a table where an array was expected.
Related errors
- symdiff: failed to convert value: %w
- %s isn't a field of struct type %s
- the math.Abs function requires a numeric argument
- Ceil operator can't be used with non-float value
- Floor operator can't be used with non-float value
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/9a7654913c9d6220.json.
Report an issue: GitHub ↗.