gohugoio/hugo · error

invalid targetType: expected either slice or map, received %

Error message

invalid targetType: expected either slice or map, received %s

What it means

Thrown by Decoder.Unmarshal (parser/metadecoders/decoder.go:154) when decoding empty data as CSV but the Decoder.TargetType is neither "map" nor "slice". With empty CSV input Hugo still needs to return the correct zero value (empty map or empty slice), and an unrecognized TargetType makes that impossible.

Source

Thrown at parser/metadecoders/decoder.go:154

		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:
			return make(map[string]any), nil
		}
	}
	var v any
	err := d.UnmarshalTo(data, f, &v)

	return v, err
}

// UnmarshalYaml unmarshals data in YAML format into v.
func UnmarshalYaml(data []byte, v any) error {
	if err := yaml.Unmarshal(data, v); err != nil {
		return err
	}
	if err := validateAliasLimitForCollections(v, calculateCollectionAliasLimit(len(data))); err != nil {
		return err

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Set Decoder.TargetType to exactly "slice" or "map" when handling CSV.
  2. Use the package-level Default decoder which sets TargetType="slice" unless you need map mode.
  3. Avoid passing empty CSV data, or guard for emptiness before calling Unmarshal.

Example fix

// before
dec := metadecoders.Decoder{Format: "csv", TargetType: "object"}
v, err := dec.Unmarshal(data, metadecoders.CSV)

// after
dec := metadecoders.Decoder{Format: "csv", TargetType: "slice"}
v, err := dec.Unmarshal(data, metadecoders.CSV)
Defensive patterns

Strategy: validation

Validate before calling

// TargetType must be map or slice for CSV.
func validCSVTargetType(t string) bool {
    return t == "map" || t == "slice"
}

Try / catch

if _, err := dec.Unmarshal(data, metadecoders.CSV); err != nil {
    return fmt.Errorf("CSV decode config invalid: %w", err)
}

Prevention

When it happens

Trigger: Constructing a Decoder with TargetType set to something other than "map" or "slice" (e.g. "object", "list", "", or a typo) and then unmarshalling empty CSV data; using a custom Decoder with a bad TargetType field for CSV resources.

Common situations: Programmatic creation of a metadecoders.Decoder for CSV resources with a misspelled TargetType; relying on the zero value ("") which is invalid for CSV (Default uses "slice").

Related errors


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