{"id":"839a1e3b2228f946","repo":"gohugoio/hugo","slug":"invalid-precision-d","errorCode":null,"errorMessage":"invalid precision: %d","messagePattern":"invalid precision: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/lang/lang.go","lineNumber":115,"sourceCode":"//\n// The return value is formatted with at least two decimal places.\nfunc (ns *Namespace) FormatAccounting(precision, currency, number any) (string, error) {\n\tp, n, err := ns.castPrecisionNumber(precision, number)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn ns.translator.FormatAccounting(n, p, cast.ToString(currency)), nil\n}\n\nfunc (ns *Namespace) castPrecisionNumber(precision, number any) (int, float64, error) {\n\tp, err := cast.ToIntE(precision)\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\t// Sanity check.\n\tif p > 20 {\n\t\treturn 0, 0, fmt.Errorf(\"invalid precision: %d\", precision)\n\t}\n\n\tn, err := cast.ToFloat64E(number)\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\treturn p, n, nil\n}\n\n// FormatNumberCustom formats a number with the given precision. The first\n// options parameter is a space-delimited string of characters to represent\n// negativity, the decimal point, and grouping. The default value is `- . ,`.\n// The second options parameter defines an alternate delimiting character.\n//\n// Note that numbers are rounded up at 5 or greater.\n// So, with precision set to 0, 1.5 becomes `2`, and 1.4 becomes `1`.\n//\n// For a simpler function that adapts to the current language, see FormatNumber.","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/lang/lang.go#L97-L133","documentation":"Hugo's number-formatting functions (`lang.FormatNumber`, `FormatPercent`, `FormatCurrency`, `FormatAccounting`) share `castPrecisionNumber`, which sanity-checks the precision argument and rejects any value greater than 20. Precisions above 20 exceed float64's meaningful decimal digits, so Hugo fails fast instead of producing garbage output.","triggerScenarios":"Calling `{{ lang.FormatNumber 21 512.5032 }}` or any of the four Format* functions with a precision argument that casts to an int greater than 20. Note only the upper bound is checked here; a non-numeric precision fails earlier with a cast error.","commonSituations":"Swapped argument order — Hugo's Format* functions take precision FIRST, so `{{ lang.FormatNumber 1234.56 2 }}` passes 1234 as precision and triggers this; also computed precisions from site params or front matter that are unexpectedly large.","solutions":["Check argument order: precision comes first, e.g. `{{ lang.FormatNumber 2 1234.56 }}` — the number is likely being used as the precision.","Clamp or validate any computed precision so it is between 0 and 20.","If the value comes from front matter or config, verify it is the intended decimal-places integer, not the number to format."],"exampleFix":"<!-- before (args swapped) -->\n{{ lang.FormatNumber 1234.56 2 }}\n<!-- after -->\n{{ lang.FormatNumber 2 1234.56 }}","handlingStrategy":"validation","validationCode":"{{ $p := 2 }}\n{{ if and (ge $p 0) (le $p 20) }}{{ lang.FormatNumber $p .Value }}{{ else }}{{ errorf \"precision out of range: %v\" $p }}{{ end }}","typeGuard":"{{ $ok := and (eq (printf \"%T\" $p) \"int\") (ge $p 0) }}","tryCatchPattern":"{{ with try (lang.FormatNumber $p .Value) }}{{ with .Err }}{{ warnf \"bad precision %v: %s\" $p . }}{{ else }}{{ .Value }}{{ end }}{{ end }}","preventionTips":["Clamp precision to a small non-negative integer (0–20) before calling","Cast front-matter or params-sourced precision with `int` and validate it isn't negative","Don't derive precision from user content without bounds checking"],"tags":["hugo","templates","number-formatting","localization"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}