{"record":{"id":"7ec1820653cae584","repo":"gohugoio/hugo","slug":"arguments-to-complement-must-be-slices-or-arrays","errorCode":null,"errorMessage":"arguments to complement must be slices or arrays","messagePattern":"arguments to complement must be slices or arrays","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/complement.go","lineNumber":57,"sourceCode":"\n\taset, err := collectIdentities(as...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tv := reflect.ValueOf(universe)\n\tswitch v.Kind() {\n\tcase reflect.Array, reflect.Slice:\n\t\tsl := reflect.MakeSlice(v.Type(), 0, 0)\n\t\tfor i := range v.Len() {\n\t\t\tev, _ := hreflect.Indirect(v.Index(i))\n\t\t\tif _, found := aset[normalize(ev)]; !found {\n\t\t\t\tsl = reflect.Append(sl, ev)\n\t\t\t}\n\t\t}\n\t\treturn sl.Interface(), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"arguments to complement must be slices or arrays\")\n\t}\n}\n","sourceCodeStart":39,"sourceCodeEnd":60,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/complement.go#L39-L60","documentation":"Thrown by Namespace.Complement when the LAST argument (the 'universe' set) is neither an array nor a slice. Complement returns elements in the universe not present in the preceding argument sets; the universe must be a positional iterable. Note the preceding args are validated separately by collectIdentities, so this specific error targets only the final argument.","triggerScenarios":"Calling `{{ complement $set1 \"string\" }}`, `{{ complement $set1 $someMap }}`, or `{{ .Pages | complement $lastFour }}` where `.Pages` resolved to a non-slice. The switch in Complement inspects reflect.Kind of `universe`; non Slice/Array falls to the default branch.","commonSituations":"Pipe order confusion (the universe ends up being a single page or string), front matter feeding a scalar into the universe slot, or a variable that was expected to be `.Pages` but is nil/typed differently after a refactor.","solutions":["Ensure the last argument is a slice/array: `{{ complement $exclude $allPages }}`.","Check pipe direction — Complement's last positional arg is the universe, so `{{ $all | complement $exclude }}` puts $all last correctly.","Wrap a single value: `{{ complement $exclude (slice $x) }}`.","Log the type of the universe variable before calling to diagnose."],"exampleFix":"// before\n{{ complement $exclude \"notalist\" }}\n// after\n{{ complement $exclude $allPages }}","handlingStrategy":"type-guard","validationCode":"func complementLastIsSlice(args ...any) error {\n    if len(args) < 2 { return errors.New(\"need >=2 args\") }\n    u := args[len(args)-1]\n    k := reflect.ValueOf(u).Kind()\n    if k != reflect.Slice && k != reflect.Array {\n        return fmt.Errorf(\"universe must be slice/array, got %T\", u)\n    }\n    return nil\n}","typeGuard":"func isSliceOrArray(v any) bool {\n    if v == nil { return false }\n    k := reflect.ValueOf(v).Kind()\n    return k == reflect.Slice || k == reflect.Array\n}","tryCatchPattern":null,"preventionTips":["Remember Complement's LAST argument is the universe — keep it a slice/array.","Check pipe direction so the universe lands in the last slot.","Wrap a single value in a slice before complement.","Log operand types when debugging complement failures."],"tags":["go","hugo","template","collections","complement","type-error"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}