gohugoio/hugo · error

unmarshal: %T not supported

Error message

unmarshal: %T not supported

What it means

Thrown by Decoder.UnmarshalStringTo (parser/metadecoders/decoder.go:138) when the target type 'typ' is not one of the supported cases (string, map[string]any, hmaps.Params, []any, bool, int, int64, float64). The %T names the unsupported type. This function dispatches on the concrete Go type of the destination, so an arbitrary struct or pointer triggers the default branch.

Solutions

  1. Pass one of the supported target types: string, map[string]any, hmaps.Params, []any, bool, int, int64, or float64.
  2. For decoding into arbitrary structs, use Decoder.UnmarshalTo(data, format, &myStruct) instead of UnmarshalStringTo.
  3. If a custom collection type is needed, decode into map[string]any first then convert.

Example fix

// before
var s MyStruct
v, err := dec.UnmarshalStringTo(raw, &s)

// after
v, err := dec.UnmarshalTo([]byte(raw), metadecoders.JSON, &s)
Defensive patterns

Strategy: type-guard

Validate before calling

// Only pass supported target types to UnmarshalStringTo.
func isSupportedStringTarget(typ any) bool {
    switch typ.(type) {
    case string, map[string]any, hmaps.Params, []any, bool, int, int64, float64:
        return true
    }
    return false
}

Type guard

func isSupportedStringTarget(typ any) bool {
    switch typ.(type) {
    case string, map[string]any, hmaps.Params, []any, bool, int, int64, float64:
        return true
    }
    return false
}

Try / catch

v, err := dec.UnmarshalStringTo(raw, target)
if err != nil {
    return fmt.Errorf("cannot unmarshal string into target: %w", err)
}

Prevention

When it happens

Trigger: Calling UnmarshalStringTo(data, someStruct{}) or UnmarshalStringTo(data, &myType{}) where the target is not one of the eight supported scalar/collection types; passing a custom type alias that does not match any case.

Common situations: Programmatic misuse of the metadecoders API by plugin/theme authors; passing a struct pointer expecting reflection-based decoding (use UnmarshalTo for that).

Related errors


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

Appendix: source

Thrown at parser/metadecoders/decoder.go:138

	switch typ.(type) {
	case string:
		return data, nil
	case map[string]any, hmaps.Params:
		format := d.FormatFromContentString(data)
		return d.UnmarshalToMap([]byte(data), format)
	case []any:
		// A standalone slice. Let YAML handle it.
		return d.Unmarshal([]byte(data), YAML)
	case bool:
		return cast.ToBoolE(data)
	case int:
		return cast.ToIntE(data)
	case int64:
		return cast.ToInt64E(data)
	case float64:
		return cast.ToFloat64E(data)
	default:
		return nil, fmt.Errorf("unmarshal: %T not supported", typ)
	}
}

// Unmarshal will unmarshall data in format f into an interface{}.
// This is what's needed for Hugo's /data handling.
func (d Decoder) Unmarshal(data []byte, f Format) (any, error) {
	if len(data) == 0 {
		switch f {
		case CSV:
			switch d.TargetType {
			case "map":
				return make(map[string]any), nil
			case "slice":
				return make([][]string, 0), nil
			default:
				return nil, fmt.Errorf("invalid targetType: expected either slice or map, received %s", d.TargetType)
			}
		default:

View on GitHub (pinned to 52c9bd7908)