{"record":{"id":"0043887a1365d89b","repo":"quarkusio/quarkus","slug":"cannot-coerce-to-a-bigdecimal","errorCode":null,"errorMessage":"Cannot coerce  to a BigDecimal","messagePattern":"Cannot coerce  to a BigDecimal","errorType":"exception","errorClass":"TemplateException","httpStatus":null,"severity":"error","filePath":"independent-projects/qute/core/src/main/java/io/quarkus/qute/IfSectionHelper.java","lineNumber":583,"sourceCode":"        }\n\n        static BigDecimal getDecimal(Object value) {\n            if (value instanceof BigDecimal decimal) {\n                return decimal;\n            } else if (value instanceof BigInteger bigInteger) {\n                return new BigDecimal(bigInteger);\n            } else if (value instanceof Integer integer) {\n                return BigDecimal.valueOf(integer);\n            } else if (value instanceof Long _long) {\n                return BigDecimal.valueOf(_long);\n            } else if (value instanceof Double _double) {\n                return BigDecimal.valueOf(_double);\n            } else if (value instanceof Float _float) {\n                return BigDecimal.valueOf(_float);\n            } else if (value instanceof String string) {\n                return new BigDecimal(string);\n            }\n            throw new TemplateException(\"Cannot coerce \" + value + \" to a BigDecimal\");\n        }\n\n    }\n\n    static <B extends ErrorInitializer & WithOrigin> List<Object> parseParams(List<Object> params, B block) {\n\n        replaceOperatorsAndCompositeParams(params, block);\n        int highestPrecedence = getHighestPrecedence(params);\n\n        if (!isGroupingNeeded(params)) {\n            // No operators or all of the same precedence\n            return params;\n        }\n\n        // Take the operators with highest precedence and form groups\n        // For example \"user.active && target.status == NEW && !target.voted\" becomes \"user.active && [target.status == NEW] && [!target.voted]\"\n        // The algorithm used is not very robust and should be improved later\n        List<Object> highestGroup = null;","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/core/src/main/java/io/quarkus/qute/IfSectionHelper.java#L565-L601","documentation":"When an {if} section needs numeric comparison (e.g. {if a > 1.5}), Qute coerces operand values to BigDecimal. Coercion supports Number types, BigDecimal/BigInteger and exact numeric Strings. If a value cannot be represented as a BigDecimal — typically an empty or non-numeric string — TemplateException is thrown at template evaluation time.","triggerScenarios":"Comparing a String value in an if-condition where the string is empty (note the message shows two spaces: value renders empty) or not parseable by java.math.BigDecimal, e.g. {if 'abc' > 1} or {if myParam > 5} where myParam is an empty form/query parameter.","commonSituations":"Empty HTTP request parameters or missing form fields bound to Strings used in numeric template comparisons; locale-formatted numbers like '1,5' or '12.0.1'; whitespace-only strings; config properties left blank.","solutions":["Validate/coerce the value before it reaches the template (parse to a number in code, defaulting when empty)","Ensure the String is a plain number parseable by new BigDecimal(...), e.g. '1.5' not '1,5' or ''","If empty means false, guard the condition: {#if myParam?? && myParam != '' && myParam > 5}","Compare against a string/number of the same type to avoid coercion, or pass a Number (Integer/Double) instead of String"],"exampleFix":"// before: template {#if count > 5} with count = \"\" (String)\n// after: pass a parsed Number with a default\nint parsed = raw == null || raw.isBlank() ? 0 : Integer.parseInt(raw);\ndata.put(\"count\", parsed);","handlingStrategy":"validation","validationCode":"String s = maybeNull == null ? \"\" : maybeNull.trim();\nboolean ok = !s.isEmpty() && new BigDecimal(s) is parseable; // wrap in try/catch NumberFormatException","typeGuard":"boolean isNumeric(String v) {\n    if (v == null || v.isBlank()) return false;\n    try { new java.math.BigDecimal(v.trim()); return true; }\n    catch (NumberFormatException e) { return false;\n} }","tryCatchPattern":"try {\n    template.render(data);\n} catch (TemplateException e) {\n    if (e.getMessage().contains(\"Cannot coerce\")) {\n        log.error(\"Non-numeric value used in {#if} comparison: \" + e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Validate/coerce request parameters to Numbers before putting them into template data","Never pass empty Strings into numeric template comparisons","Use dot-decimal formats only ('1.5', not '1,5')","Use Qute value resolvers/converters to normalize values"],"tags":["qute","template","numeric-coercion","bigdecimal"],"backgroundTag":"numeric-coercion-failed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}