gohugoio/hugo · error

arguments to complement must be slices or arrays

Error message

arguments to complement must be slices or arrays

What it means

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.

Solutions

  1. Ensure the last argument is a slice/array: `{{ complement $exclude $allPages }}`.
  2. Check pipe direction — Complement's last positional arg is the universe, so `{{ $all | complement $exclude }}` puts $all last correctly.
  3. Wrap a single value: `{{ complement $exclude (slice $x) }}`.
  4. Log the type of the universe variable before calling to diagnose.

Example fix

// before
{{ complement $exclude "notalist" }}
// after
{{ complement $exclude $allPages }}
Defensive patterns

Strategy: type-guard

Validate before calling

func complementLastIsSlice(args ...any) error {
    if len(args) < 2 { return errors.New("need >=2 args") }
    u := args[len(args)-1]
    k := reflect.ValueOf(u).Kind()
    if k != reflect.Slice && k != reflect.Array {
        return fmt.Errorf("universe must be slice/array, got %T", u)
    }
    return nil
}

Type guard

func isSliceOrArray(v any) bool {
    if v == nil { return false }
    k := reflect.ValueOf(v).Kind()
    return k == reflect.Slice || k == reflect.Array
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/7ec1820653cae584. Report an issue: GitHub.

Appendix: source

Thrown at tpl/collections/complement.go:57

	aset, err := collectIdentities(as...)
	if err != nil {
		return nil, err
	}

	v := reflect.ValueOf(universe)
	switch v.Kind() {
	case reflect.Array, reflect.Slice:
		sl := reflect.MakeSlice(v.Type(), 0, 0)
		for i := range v.Len() {
			ev, _ := hreflect.Indirect(v.Index(i))
			if _, found := aset[normalize(ev)]; !found {
				sl = reflect.Append(sl, ev)
			}
		}
		return sl.Interface(), nil
	default:
		return nil, fmt.Errorf("arguments to complement must be slices or arrays")
	}
}

View on GitHub (pinned to 52c9bd7908)