{"record":{"id":"96de9876990450ea","repo":"gohugoio/hugo","slug":"modulo-operator-can-t-be-used-with-non-integer-val","errorCode":null,"errorMessage":"modulo operator can't be used with non integer value","messagePattern":"modulo operator can't be used with non integer value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/math/math.go","lineNumber":166,"sourceCode":"}\n\n// MaxInt64 returns the maximum value for a signed 64-bit integer.\nfunc (ns *Namespace) MaxInt64() int64 {\n\treturn math.MaxInt64\n}\n\n// Min returns the smaller of all numbers in inputs. Any slices in inputs are flattened.\nfunc (ns *Namespace) Min(inputs ...any) (minimum float64, err error) {\n\treturn ns.applyOpToScalarsOrSlices(\"Min\", math.Min, inputs...)\n}\n\n// Mod returns n1 % n2.\nfunc (ns *Namespace) Mod(n1, n2 any) (int64, error) {\n\tai, erra := cast.ToInt64E(n1)\n\tbi, errb := cast.ToInt64E(n2)\n\n\tif erra != nil || errb != nil {\n\t\treturn 0, errors.New(\"modulo operator can't be used with non integer value\")\n\t}\n\n\tif bi == 0 {\n\t\treturn 0, errors.New(\"the number can't be divided by zero at modulo operation\")\n\t}\n\n\treturn ai % bi, nil\n}\n\n// ModBool returns the boolean of n1 % n2.  If n1 % n2 == 0, return true.\nfunc (ns *Namespace) ModBool(n1, n2 any) (bool, error) {\n\tres, err := ns.Mod(n1, n2)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn res == int64(0), nil\n}","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/math/math.go#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass integer values (int or integer-valued) to math.Mod.","Truncate floats to int first if appropriate, or restructure to avoid modulo on floats.","Add an integer default: {{ math.Mod (.Param \"n\" | default 0) 2 }}.","Guard that both operands are integers before calling."],"exampleFix":"// before\n{{ math.Mod .Params.ratio 2 }}\n\n// after\n{{ $n := int (.Params.count | default 0) }}\n{{ math.Mod $n 2 }}","handlingStrategy":"type-guard","validationCode":"// math.Mod needs integers; coerce or guard before calling:\n{{ $n := int (.Param \"count\" | default 0) }}\n{{ math.Mod $n 2 }}","typeGuard":"// Go caller: Mod only accepts int64-convertible values:\nfunc isIntegerLike(v any) bool {\n    switch reflect.ValueOf(v).Kind() {\n    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,\n        reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n        return true\n    }\n    if s, ok := v.(string); ok {\n        _, err := strconv.ParseInt(s, 10, 64)\n        return err == nil\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Pass integer values to math.Mod (floats are rejected).","Coerce with int where appropriate.","Default unset params to an integer."],"tags":["hugo","template","math","type-validation","modulo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}