gohugoio/hugo · error

first argument must be a map

Error message

first argument must be a map

What it means

When `transform.Unmarshal` is called with two arguments, the first must be an options map (`map[string]any`); the second is the data. If the first argument is anything else — a string, a Resource, the data itself — this error is returned. It commonly indicates the arguments are in the wrong order.

Source

Thrown at tpl/transform/unmarshal.go:51

)

// Unmarshal unmarshals the data given, which can be either a string, json.RawMessage
// or a Resource. Supported formats are JSON, TOML, YAML, and CSV.
// You can optionally provide an options map as the first argument.
func (ns *Namespace) Unmarshal(args ...any) (any, error) {
	if len(args) < 1 || len(args) > 2 {
		return nil, errors.New("unmarshal takes 1 or 2 arguments")
	}

	var data any
	decoder := metadecoders.Default

	if len(args) == 1 {
		data = args[0]
	} else {
		m, ok := args[0].(map[string]any)
		if !ok {
			return nil, errors.New("first argument must be a map")
		}

		var err error

		data = args[1]
		decoder, err = decodeDecoder(m)
		if err != nil {
			return nil, fmt.Errorf("failed to decode options: %w", err)
		}
	}

	if r, ok := data.(resource.UnmarshableResource); ok {
		key := r.Key()

		if key == "" {
			return nil, errors.New("no Key set in Resource")
		}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Put the options map first and the data second: `{{ transform.Unmarshal (dict "delimiter" ";") $data }}`.
  2. Wrap format/delimiter settings in a dict — a bare string like "csv" is not accepted.
  3. If you don't need options, drop the first argument and call with just the data.

Example fix

<!-- before -->
{{ transform.Unmarshal $data (dict "delimiter" ";") }}
<!-- after -->
{{ transform.Unmarshal (dict "delimiter" ";") $data }}
Defensive patterns

Strategy: type-guard

Validate before calling

{{ $opts := dict "delimiter" ";" }}
{{ $d := unmarshal $opts $csv }}

Type guard

{{/* ensure options is a map before the 2-arg form */}}
{{ if reflect.IsMap $opts }}{{ $d = unmarshal $opts $data }}{{ else }}{{ $d = unmarshal $data }}{{ end }}

Prevention

When it happens

Trigger: `{{ transform.Unmarshal $data $opts }}` (data first, options second — reversed); `{{ transform.Unmarshal "csv" $data }}` (passing a format name string instead of a dict); `{{ transform.Unmarshal $resource (dict ...) }}`.

Common situations: Assuming the options map comes after the data (many Hugo functions vary here — for Unmarshal, options come first); trying to specify the format as a plain string instead of `(dict "format" "csv")`; a `.Params` value expected to be a map but authored as a string in front matter.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/a88bfba4732ce6c3.json. Report an issue: GitHub ↗.