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
- Put the options map first and the data second: `{{ transform.Unmarshal (dict "delimiter" ";") $data }}`.
- Wrap format/delimiter settings in a dict — a bare string like "csv" is not accepted.
- 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
- In the two-argument form the FIRST argument must be the options dict, not the data
- Build options with `dict`, never a string or slice
- If you have no options, use the single-argument form
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
- type %T not supported
- arguments to symdiff must be slices or arrays
- can't iterate over %T
- text must be a string
- unmarshal takes 1 or 2 arguments
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/a88bfba4732ce6c3.json.
Report an issue: GitHub ↗.