gohugoio/hugo · error

can't apply the operator to the values

Error message

can't apply the operator to the values

What it means

common/math.DoArithmetic implements Hugo's arithmetic template functions (add, sub, mul, div) via reflection. It only supports int/uint/float operands (plus string+string concatenation for '+'). If either operand's reflect.Kind is anything else — bool, nil, map, slice, time, or an unparsed string — it returns this error.

Source

Thrown at common/math/math.go:51

		switch bv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			isInt = true
			bi = bv.Int()
		case reflect.Float32, reflect.Float64:
			isFloat = true
			af = float64(ai) // may overflow
			bf = bv.Float()
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			bu = bv.Uint()
			if ai >= 0 {
				isUint = true
				au = uint64(ai)
			} else {
				isInt = true
				bi = int64(bu) // may overflow
			}
		default:
			return nil, errors.New("can't apply the operator to the values")
		}
	case reflect.Float32, reflect.Float64:
		isFloat = true
		af = av.Float()
		switch bv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			bf = float64(bv.Int()) // may overflow
		case reflect.Float32, reflect.Float64:
			bf = bv.Float()
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			bf = float64(bv.Uint()) // may overflow
		default:
			return nil, errors.New("can't apply the operator to the values")
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		au = av.Uint()
		switch bv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Convert operands explicitly with `int`, `float`, or `string` before the math call, e.g. `{{ add (int .Params.count) 1 }}`.
  2. Guard against nil/missing params with `default`, e.g. `{{ add (.Params.count | default 0) 1 }}`.
  3. Fix the source data so numbers are unquoted in front matter/config/data files.

Example fix

{{/* before */}}
{{ add .Params.count 1 }}  {{/* count: "3" in front matter */}}

{{/* after */}}
{{ add (int (.Params.count | default 0)) 1 }}
Defensive patterns

Strategy: type-guard

Validate before calling

// Both operands must be numeric (or both strings for +)
if !isNumeric(a) || !isNumeric(b) { /* cast first */ }

Type guard

func isNumeric(v any) bool {
	switch reflect.ValueOf(v).Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Float32, reflect.Float64:
		return true
	}
	return false
}

Try / catch

v, err := math.DoArithmetic(a, b, op)
if err != nil {
	// report which operand had the wrong type; do not substitute a default value
}

Prevention

When it happens

Trigger: Calling `add`, `sub`, `mul`, or `div` in a template where an operand is not numeric: e.g. `{{ add .Params.count 1 }}` when the front matter value is the string "3", `{{ sub "a" "b" }}`, adding a nil value from a missing param, or `add` with a bool/map/slice.

Common situations: Front matter or config values quoted as strings (weight: "10"), missing .Params keys yielding nil, values coming from data/JSON where numbers were encoded as strings, or trying to use `add` for string concat with a non-string second operand (string concat only works when both are strings and op is '+').

Related errors


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