{"id":"3dfd87e8dac1bd4b","repo":"gohugoio/hugo","slug":"unmarshal-takes-1-or-2-arguments","errorCode":null,"errorMessage":"unmarshal takes 1 or 2 arguments","messagePattern":"unmarshal takes 1 or 2 arguments","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/transform/unmarshal.go","lineNumber":40,"sourceCode":"\t\"github.com/gohugoio/hugo/resources\"\n\t\"github.com/gohugoio/hugo/resources/resource\"\n\n\t\"github.com/gohugoio/hugo/common/hashing\"\n\t\"github.com/gohugoio/hugo/common/types\"\n\n\t\"github.com/mitchellh/mapstructure\"\n\n\t\"github.com/gohugoio/hugo/parser/metadecoders\"\n\n\t\"github.com/spf13/cast\"\n)\n\n// Unmarshal unmarshals the data given, which can be either a string, json.RawMessage\n// or a Resource. Supported formats are JSON, TOML, YAML, and CSV.\n// You can optionally provide an options map as the first argument.\nfunc (ns *Namespace) Unmarshal(args ...any) (any, error) {\n\tif len(args) < 1 || len(args) > 2 {\n\t\treturn nil, errors.New(\"unmarshal takes 1 or 2 arguments\")\n\t}\n\n\tvar data any\n\tdecoder := metadecoders.Default\n\n\tif len(args) == 1 {\n\t\tdata = args[0]\n\t} else {\n\t\tm, ok := args[0].(map[string]any)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"first argument must be a map\")\n\t\t}\n\n\t\tvar err error\n\n\t\tdata = args[1]\n\t\tdecoder, err = decodeDecoder(m)\n\t\tif err != nil {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/transform/unmarshal.go#L22-L58","documentation":"`transform.Unmarshal` requires either one argument (the data: a string, json.RawMessage, or Resource) or two (an options map first, then the data). Zero arguments or three-plus fail this arity check immediately, before any decoding is attempted.","triggerScenarios":"`{{ transform.Unmarshal }}` with nothing; `{{ transform.Unmarshal $opts $data $extra }}`; pipeline mistakes like `{{ $a $b | transform.Unmarshal $c }}` where the pipe adds a final argument beyond two.","commonSituations":"Forgetting that piped values count as the last argument (`$data | transform.Unmarshal $opts` is fine — two args — but adding more breaks it); passing CSV options as separate arguments instead of one dict; splitting an unquoted string into multiple arguments.","solutions":["Call it as `transform.Unmarshal DATA` or `transform.Unmarshal OPTIONS_MAP DATA`.","Bundle all options into a single dict: `{{ transform.Unmarshal (dict \"delimiter\" \";\") $csv }}`.","When piping, remember the piped value is appended as the final argument — only the options map should precede it."],"exampleFix":"<!-- before -->\n{{ transform.Unmarshal \"delimiter\" \";\" $csv }}\n<!-- after -->\n{{ transform.Unmarshal (dict \"delimiter\" \";\") $csv }}","handlingStrategy":"validation","validationCode":"{{/* unmarshal (options?, data): */}}\n{{ $d := unmarshal $yaml }} or {{ $d := unmarshal (dict \"delimiter\" \";\") $csv }}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call transform.Unmarshal with 1 or 2 args: optional options map, then the data","When piping, the piped resource/string is the last argument — pass only the options map explicitly","Don't pass multiple documents; unmarshal one at a time"],"tags":["hugo","templates","unmarshal","arguments"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}