gohugoio/hugo · error

can't apply the operator to the values

Error message

can't apply the operator to the values

What it means

DoArithmetic uses reflection on both operands; this throw (math.go:51) is the default branch when the first operand is an int kind but the second operand's reflect.Kind is not int/float/uint (e.g. string, bool, nil, struct), so the operator (+,-,*,/) cannot be applied.

Solutions

  1. Ensure both operands are numeric (int/uint/float) before calling math functions
  2. Coerce front matter values to numbers with int/float in templates
  3. Add a default/fallback so the operand is never nil or a string

Example fix

{{/* before */}}
{{ add .Params.qty "5" }}
{{/* after */}}
{{ add .Params.qty (int "5") }}
Defensive patterns

Strategy: type-guard

Validate before calling

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
}
if !isNumeric(b) { /* coerce, default, or skip */ }

Type guard

func isNumeric(v any) bool { /* body as in validationCode */ }

Try / catch

if r, err := math.DoArithmetic(a, b, op); err != nil {
    // coerce operands or substitute a numeric default
} else { use(r) }

Prevention

When it happens

Trigger: Calling a Hugo math template function (add/sub/mul/div) with an int first operand and a non-numeric second operand, e.g. `{{ add 1 "x" }}` or `{{ add .Qty nil }}`.

Common situations: Template receives a string from front matter where a number was expected; a nil/missing value reaching arithmetic; a bool passed accidentally.

Related errors


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

Appendix: 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 52c9bd7908)