gohugoio/hugo · error

arguments to symdiff must be slices or arrays

Error message

arguments to symdiff must be slices or arrays

What it means

Thrown by SymDiff when either s1 or s2 is neither an array nor a slice. SymDiff computes the symmetric difference by iterating both operands; each must be a positional iterable. The default branch of the per-operand switch rejects maps, strings, structs, scalars, etc.

Solutions

  1. Pass only slices/arrays to symdiff: `{{ symdiff $sliceA $sliceB }}`.
  2. Wrap a single value: `{{ symdiff (slice $x) $sliceB }}`.
  3. Convert a map's values to a slice first.
  4. Verify both operands' types before calling.

Example fix

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

Strategy: type-guard

Validate before calling

func symdiffArgsValid(s1, s2 any) error {
    for i, s := range []any{s1, s2} {
        k := reflect.ValueOf(s).Kind()
        if k != reflect.Slice && k != reflect.Array {
            return fmt.Errorf("arg %d must be slice/array, got %T", i, s)
        }
    }
    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 `{{ symdiff $aMap $bSlice }}`, `{{ symdiff "abc" $bSlice }}`, or `{{ symdiff 42 $b }}`. Each operand is reflect-checked; non Slice/Array falls to the default branch. Note the argument order is (s2, s1) in the Go signature but both are validated.

Common situations: Author passes a single value or map expecting element-wise diff, or a variable resolved to a non-collection. Common with data that is sometimes a slice and sometimes a scalar.

Related errors


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

Appendix: source

Thrown at tpl/collections/symdiff.go:63

				sliceElemType = sliceType.Elem()
				slice = reflect.MakeSlice(sliceType, 0, 0)
			}

			for i := range v.Len() {
				ev, _ := hreflect.Indirect(v.Index(i))
				key := normalize(ev)

				// Append if the key is not in their intersection.
				if ids1[key] != ids2[key] {
					v, err := convertValue(ev, sliceElemType)
					if err != nil {
						return nil, fmt.Errorf("symdiff: failed to convert value: %w", err)
					}
					slice = reflect.Append(slice, v)
				}
			}
		default:
			return nil, fmt.Errorf("arguments to symdiff must be slices or arrays")
		}
	}

	return slice.Interface(), nil
}

View on GitHub (pinned to 52c9bd7908)