gohugoio/hugo · error
complement needs at least two arguments
Error message
complement needs at least two arguments
What it means
`collections.Complement` returns the elements of its last argument that appear in none of the earlier ones (tpl/collections/complement.go:32-35). With fewer than two arguments there is no universe/exclusion pair to compute — one collection alone has no complement — so Hugo rejects the call up front. The last-argument-is-the-universe design exists so it pipelines naturally: `{{ .Pages | complement $last4 }}`.
Source
Thrown at tpl/collections/complement.go:34
import (
"errors"
"fmt"
"reflect"
"github.com/gohugoio/hugo/common/hreflect"
)
// Complement gives the elements in the last element of ls that are not in
// any of the others.
//
// All elements of ls must be slices or arrays of comparable types.
//
// The reasoning behind this rather clumsy API is so we can do this in the templates:
//
// {{ $c := .Pages | complement $last4 }}
func (ns *Namespace) Complement(ls ...any) (any, error) {
if len(ls) < 2 {
return nil, errors.New("complement needs at least two arguments")
}
universe := ls[len(ls)-1]
as := ls[:len(ls)-1]
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)View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Provide at least one exclusion collection plus the universe: `{{ $rest := .Pages | complement $featured }}`.
- If the exclusion set can be empty, still pass it as an empty slice (`default (slice)`) rather than omitting the argument.
- If you didn't intend a set operation, use `where` or `first` instead.
Example fix
<!-- before -->
{{ $rest := complement .Pages }}
<!-- after -->
{{ $featured := first 4 .Pages }}
{{ $rest := .Pages | complement $featured }} Defensive patterns
Strategy: validation
Validate before calling
{{ if lt (len $sets) 2 }}
{{ errorf "complement needs at least two collections, got %d" (len $sets) }}
{{ end }}
{{ $result := collections.Complement $exclude $universe }} Prevention
- Always pass at least two collections: the last argument is the source, earlier ones are excluded
- When building the argument list dynamically, check its length ≥ 2 first
- Remember argument order — `complement $toRemove $all`, not the reverse
When it happens
Trigger: Calling `{{ complement .Pages }}` with a single collection, or `{{ complement }}` with none — typically by not realizing the piped value counts as the final argument and at least one exclusion set must be passed before it.
Common situations: Misreading the docs and expecting complement of one set against the site automatically; a template refactor that drops the exclusion variable; passing the exclusion set conditionally so it's absent on some pages.
Related errors
- symdiff: failed to convert value: %w
- arguments to symdiff must be slices or arrays
- errWrongArgStructure
- errKeyIsEmptyString
- arguments to complement must be slices or arrays
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/126e4be5d53d0913.json.
Report an issue: GitHub ↗.