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
- Convert operands explicitly with `int`, `float`, or `string` before the math call, e.g. `{{ add (int .Params.count) 1 }}`.
- Guard against nil/missing params with `default`, e.g. `{{ add (.Params.count | default 0) 1 }}`.
- 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
- Cast template values with `int`/`float` before arithmetic (front-matter values are often strings).
- Only use string operands with '+', never with -, *, /.
- Validate user-supplied params at the boundary before passing them to math helpers.
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
- arguments to complement must be slices or arrays
- %s isn't a key of map type %s
- %s is neither a struct field, a method nor a map element of
- type %T not supported in Resource transformations
- errMustTwoNumbersError
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/ca3088be31b124fe.json.
Report an issue: GitHub ↗.