gohugoio/hugo · error

modulo operator can't be used with non integer value

Error message

modulo operator can't be used with non integer value

What it means

Thrown by math.Mod (tpl/math/math.go:166) when either operand cannot be converted to an int64 via cast.ToInt64E. Mod computes n1 % n2 and requires integer inputs (not floats); a non-integer string, nil, bool, struct, slice, or a float like 1.5 triggers this. Note Mod only accepts integers, unlike Abs/Ceil which accept floats.

Solutions

  1. Pass integer values (int or integer-valued) to math.Mod.
  2. Truncate floats to int first if appropriate, or restructure to avoid modulo on floats.
  3. Add an integer default: {{ math.Mod (.Param "n" | default 0) 2 }}.
  4. Guard that both operands are integers before calling.

Example fix

// before
{{ math.Mod .Params.ratio 2 }}

// after
{{ $n := int (.Params.count | default 0) }}
{{ math.Mod $n 2 }}
Defensive patterns

Strategy: type-guard

Validate before calling

// math.Mod needs integers; coerce or guard before calling:
{{ $n := int (.Param "count" | default 0) }}
{{ math.Mod $n 2 }}

Type guard

// Go caller: Mod only accepts int64-convertible values:
func isIntegerLike(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:
        return true
    }
    if s, ok := v.(string); ok {
        _, err := strconv.ParseInt(s, 10, 64)
        return err == nil
    }
    return false
}

Prevention

When it happens

Trigger: Calling {{ math.Mod .A .B }} where either value is a float (1.5), a non-numeric string, nil, or bool; passing a numeric string that is not an integer.

Common situations: Passing a float where an int was assumed; nil from an unset param; using a value from a sum that produced a float; assuming Mod accepts any number.

Related errors


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

Appendix: source

Thrown at tpl/math/math.go:166

}

// MaxInt64 returns the maximum value for a signed 64-bit integer.
func (ns *Namespace) MaxInt64() int64 {
	return math.MaxInt64
}

// Min returns the smaller of all numbers in inputs. Any slices in inputs are flattened.
func (ns *Namespace) Min(inputs ...any) (minimum float64, err error) {
	return ns.applyOpToScalarsOrSlices("Min", math.Min, inputs...)
}

// Mod returns n1 % n2.
func (ns *Namespace) Mod(n1, n2 any) (int64, error) {
	ai, erra := cast.ToInt64E(n1)
	bi, errb := cast.ToInt64E(n2)

	if erra != nil || errb != nil {
		return 0, errors.New("modulo operator can't be used with non integer value")
	}

	if bi == 0 {
		return 0, errors.New("the number can't be divided by zero at modulo operation")
	}

	return ai % bi, nil
}

// ModBool returns the boolean of n1 % n2.  If n1 % n2 == 0, return true.
func (ns *Namespace) ModBool(n1, n2 any) (bool, error) {
	res, err := ns.Mod(n1, n2)
	if err != nil {
		return false, err
	}

	return res == int64(0), nil
}

View on GitHub (pinned to 52c9bd7908)