gohugoio/hugo · error

unable to cast %#v of type %T to []map[string]interface

Error message

unable to cast %#v of type %T to []map[string]interface{}

What it means

Returned by hmaps.ToSliceStringMap when the input is not one of the supported shapes ([]map[string]any, Params, map[string]any, or []any). The function normalizes heterogeneous config/frontmatter into a slice of maps; any other Go type falls through to the default branch and yields this error with the value and its type.

Solutions

  1. Re-shape the input to []map[string]any or []any whose elements are map[string]any.
  2. If you have map[string]string, convert via ToStringMapE first.
  3. Validate the decoded structure with a type assertion before calling ToSliceStringMap.

Example fix

// before
hmaps.ToSliceStringMap([]string{"a","b"})
// after
m := []map[string]any{{"value":"a"},{"value":"b"}}
hmaps.ToSliceStringMap(m)
Defensive patterns

Strategy: type-guard

Validate before calling

func isSliceStringMapable(v any) bool {
  switch v.(type) {
  case []map[string]any, hmaps.Params, map[string]any, []any, nil: return true
  }
  return false
}

Type guard

func isSliceStringMapable(v any) bool { _, ok := v.([]map[string]any); return ok || isSliceStringMapable(v) }

Prevention

When it happens

Trigger: Calling ToSliceStringMap with a struct, a []string, a number, `map[string]string`, or any type not in the switch arms of maps.go:95-113.

Common situations: Decoding menu entries, output-format definitions, or taxonomy params where the YAML/TOML decoded type does not match the expected nested-map shape (e.g. a scalar where a list of maps was expected).

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/5f99470d0f4648f2. Report an issue: GitHub.

Appendix: source

Thrown at common/hmaps/maps.go:112

// ToSliceStringMap converts in to []map[string]interface{}.
func ToSliceStringMap(in any) ([]map[string]any, error) {
	switch v := in.(type) {
	case []map[string]any:
		return v, nil
	case Params:
		return []map[string]any{v}, nil
	case map[string]any:
		return []map[string]any{v}, nil
	case []any:
		var s []map[string]any
		for _, entry := range v {
			if vv, ok := entry.(map[string]any); ok {
				s = append(s, vv)
			}
		}
		return s, nil
	default:
		return nil, fmt.Errorf("unable to cast %#v of type %T to []map[string]interface{}", in, in)
	}
}

// LookupEqualFold finds key in m with case insensitive equality checks.
func LookupEqualFold[T any | string](m map[string]T, key string) (T, string, bool) {
	if v, found := m[key]; found {
		return v, key, true
	}
	for k, v := range m {
		if strings.EqualFold(k, key) {
			return v, k, true
		}
	}
	var s T
	return s, "", false
}

// MergeShallow merges src into dst, but only if the key does not already exist in dst.

View on GitHub (pinned to 52c9bd7908)