gohugoio/hugo · error

requires at least 2 arguments

Error message

requires at least 2 arguments

What it means

Hugo's `strings.ReplacePairs` is variadic: the last argument is the source string and everything before it is old/new replacement pairs (as a slice or inline). With fewer than 2 arguments there is no way to have both a source string and at least one pair specification, so Hugo rejects the call up front.

Source

Thrown at tpl/strings/strings.go:265

	if len(limit) == 0 {
		return strings.ReplaceAll(ss, so, sn), nil
	}

	lim, err := cast.ToIntE(limit[0])
	if err != nil {
		return "", err
	}

	return strings.Replace(ss, so, sn, lim), nil
}

// ReplacePairs returns a copy of a string with multiple replacements performed
// in a single pass. The last argument is the source string. Preceding arguments
// are old/new string pairs, either as a slice or as individual arguments.
func (ns *Namespace) ReplacePairs(args ...any) (string, error) {
	if len(args) < 2 {
		return "", fmt.Errorf("requires at least 2 arguments")
	}

	ss, err := cast.ToStringE(args[len(args)-1])
	if err != nil {
		return "", err
	}

	var p []string
	if len(args) == 2 {
		// slice form: ReplacePairs (slice "a" "b") "s"
		if !hreflect.IsSlice(args[0]) {
			return "", fmt.Errorf("with 2 arguments, the first must be a slice of replacement pairs, got %T", args[0])
		}
		p, err = cast.ToStringSliceE(args[0])
		if err != nil {
			return "", err
		}
	}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Provide both a pairs argument and the source: slice form `{{ strings.ReplacePairs (slice "a" "b") $src }}` or inline form `{{ strings.ReplacePairs "a" "b" $src }}`.
  2. Remember the source string comes LAST — this differs from `replace`.
  3. If pairs are built dynamically, verify the slice is non-empty before calling.

Example fix

<!-- before -->
{{ strings.ReplacePairs $src }}
<!-- after -->
{{ strings.ReplacePairs (slice "old" "new") $src }}
Defensive patterns

Strategy: validation

Validate before calling

{{ if ge (len $pairs) 2 }}{{ strings.Replacer $s $pairs }}{{ end }}

Try / catch

if len(args) < 2 {
    return "", errors.New("need at least old/new pair")
}
out, err := ns.Replacer(args...)

Prevention

When it happens

Trigger: Calling `{{ strings.ReplacePairs "source" }}` with only the source string, or `{{ strings.ReplacePairs }}` with nothing — e.g. building the argument list dynamically and ending up with an empty/singleton set, or piping a lone string: `{{ "s" | strings.ReplacePairs }}`.

Common situations: Misunderstanding the signature (expecting a `replace`-like `old new src` order but supplying only the source); a `with`/`range` construct that drops the pairs variable so only the piped source remains; slice of pairs evaluating to nothing and being spread incorrectly.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/0eeb5a114e22f537.json. Report an issue: GitHub ↗.