gohugoio/hugo · error

arguments must be slices or arrays

Error message

arguments must be slices or arrays

What it means

Thrown by collectIdentities (reflect_helpers.go) when any sequence passed to it is neither array nor slice. collectIdentities builds a normalized identity set for set operations; it is called by Complement (for the exclusion args) and SymDiff. The default branch rejects maps, strings, structs, scalars, etc.

Source

Thrown at tpl/collections/reflect_helpers.go:73

// collects identities from the slices in seqs into a set. Numeric values are normalized,
// pointers unwrapped.
func collectIdentities(seqs ...any) (map[any]bool, error) {
	seen := make(map[any]bool)
	for _, seq := range seqs {
		v := reflect.ValueOf(seq)
		switch v.Kind() {
		case reflect.Array, reflect.Slice:
			for i := range v.Len() {
				ev, _ := hreflect.Indirect(v.Index(i))

				if !ev.Type().Comparable() {
					return nil, errors.New("elements must be comparable")
				}

				seen[normalize(ev)] = true
			}
		default:
			return nil, fmt.Errorf("arguments must be slices or arrays")
		}
	}

	return seen, nil
}

// We have some different numeric and string types that we try to behave like
// they were the same.
func convertValue(v reflect.Value, to reflect.Type) (reflect.Value, error) {
	if v.Type().AssignableTo(to) {
		return v, nil
	}
	switch kind := to.Kind(); {
	case kind == reflect.String:
		return hreflect.ToStringValueE(v)
	case hreflect.IsNumber(kind):
		return convertNumber(v, to)
	default:

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Pass only slices/arrays to Complement and SymDiff operands.
  2. Convert a map's keys or values to a slice before calling.
  3. Wrap a single value: `{{ symdiff (slice $x) $other }}`.
  4. Verify each operand's type at the call site.

Example fix

// before
{{ symdiff $aMap $sliceB }}
// after
{{ symdiff (slice 1 2 3) $sliceB }}
Defensive patterns

Strategy: type-guard

Validate before calling

func allArgsSliceOrArray(args ...any) error {
    for _, a := range args {
        k := reflect.ValueOf(a).Kind()
        if k != reflect.Slice && k != reflect.Array {
            return fmt.Errorf("arg must be slice/array, got %T", a)
        }
    }
    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 or SymDiff with a non-slice/array among the operands — e.g. `{{ complement $aMap $universe }}` (where the map is an exclusion arg, not the universe) or `{{ symdiff $aString $other }}`. Each seq is reflect-checked; non Slice/Array hits the default branch.

Common situations: Author passes a map where a slice was expected, a single page object, or a string. Often confused with the universe-specific Complement error (625) — this one targets the auxiliary set members.

Related errors


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