{"id":"cd2c347f28043650","repo":"gohugoio/hugo","slug":"expected-slice-of-resource-objects-received-t-in","errorCode":null,"errorMessage":"expected slice of Resource objects, received %T instead","messagePattern":"expected slice of Resource objects, received %T instead","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/resources/resources.go","lineNumber":215,"sourceCode":"}\n\n// Concat concatenates a slice of Resource objects. These resources must\n// (currently) be of the same Media Type.\nfunc (ns *Namespace) Concat(targetPathIn any, r any) (resource.Resource, error) {\n\ttargetPath, err := cast.ToStringE(targetPathIn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar rr resource.Resources\n\n\tswitch v := r.(type) {\n\tcase resource.Resources:\n\t\trr = v\n\tcase resource.ResourcesConverter:\n\t\trr = v.ToResources()\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"expected slice of Resource objects, received %T instead\", r)\n\t}\n\n\tif len(rr) == 0 {\n\t\treturn nil, errors.New(\"must provide one or more Resource objects to concat\")\n\t}\n\n\treturn ns.bundlerClient.Concat(targetPath, rr)\n}\n\n// FromString creates a Resource from a string published to the relative target path.\nfunc (ns *Namespace) FromString(targetPathIn, contentIn any) (resource.Resource, error) {\n\ttargetPath, err := cast.ToStringE(targetPathIn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcontent, err := cast.ToStringE(contentIn)\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/resources/resources.go#L197-L233","documentation":"`resources.Concat` requires its second argument to be a `resource.Resources` slice (or something convertible via `ResourcesConverter`). Passing a single Resource, a plain slice built with `slice` containing non-resources, or any other type hits the default case of the type switch and fails with the received type.","triggerScenarios":"`{{ resources.Concat \"js/bundle.js\" $oneResource }}` passing a single resource instead of a slice; passing a `[]any` that contains strings/paths rather than Resource objects; passing the result of `readDir` or a string glob rather than `resources.Match`.","commonSituations":"Forgetting to wrap a single resource in `slice`; building the list from file paths instead of `resources.Get` results; mixing nil entries from failed `resources.Get` calls into the slice (making it a generic slice).","solutions":["Wrap resources in `slice`: `resources.Concat \"js/bundle.js\" (slice $a $b)`.","Use `resources.Match \"js/*.js\"` to get a proper Resources slice directly.","Ensure every element is a Resource — check `resources.Get` results for nil before appending."],"exampleFix":"<!-- before -->\n{{ $bundle := resources.Concat \"js/bundle.js\" $main }}\n<!-- after -->\n{{ $bundle := resources.Concat \"js/bundle.js\" (slice $main) }}","handlingStrategy":"type-guard","validationCode":"{{ $css := slice (resources.Get \"a.css\") (resources.Get \"b.css\") }}{{ $bundle := $css | resources.Concat \"bundle.css\" }}","typeGuard":"{{ $allResources := true }}{{ range $r := $items }}{{ if not (reflect.IsMap (dict)) }}{{ end }}{{ end }}{{/* practically: ensure every element came from resources.Get / .Resources */}}","tryCatchPattern":"{{ with try (resources.Concat \"bundle.css\" $items) }}{{ with .Err }}{{ errorf \"concat failed: %s\" . }}{{ end }}{{ end }}","preventionTips":["Pass a slice of Resource objects (from resources.Get, .Resources, etc.), not strings or paths","Filter out nils: resources.Get returns nil for missing files — check `with` before appending","Don't mix plain strings with resources in the slice"],"tags":["hugo","resources","concat","type-mismatch"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}