{"record":{"id":"d7204b50a2ab857e","repo":"hibernate/hibernate-orm","slug":"unable-to-coerce-value-s-s-to-bigdecimal","errorCode":null,"errorMessage":"Unable to coerce value [%s (%s)] to BigDecimal","messagePattern":"Unable to coerce value \\[(.+?) \\((.+?)\\)\\] to BigDecimal","errorType":"exception","errorClass":"CoercionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BigDecimalJavaType.java","lineNumber":141,"sourceCode":"\n\t@Override\n\tpublic long getDefaultSqlLength(Dialect dialect, JdbcType jdbcType) {\n\t\treturn getDefaultSqlPrecision( dialect, jdbcType ) + 2;\n\t}\n\n\t@Override\n\tpublic int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {\n\t\treturn dialect.getDefaultDecimalPrecision();\n\t}\n\n\t@Override\n\tpublic @Nullable BigDecimal coerce(@Nullable Object value) {\n\t\tif ( value == null ) {\n\t\t\treturn null;\n\t\t}\n\t\tfinal var coerced = coerceOrNull( value );\n\t\tif ( coerced == null ) {\n\t\t\tthrow new CoercionException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Unable to coerce value [%s (%s)] to BigDecimal\",\n\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\tvalue.getClass().getName()\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\treturn coerced;\n\t}\n\n\t@Override\n\tpublic @Nullable BigDecimal coerceOrNull(@Nonnull Object value) {\n\t\tif ( value instanceof BigDecimal bigDecimal ) {\n\t\t\treturn bigDecimal;\n\t\t}\n\n\t\tif ( value instanceof Number number ) {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BigDecimalJavaType.java#L123-L159","documentation":"BigDecimalJavaType.coerce is Hibernate's implicit value coercion used when binding values whose type differs from the attribute/parameter type (Hibernate 6+). It accepts BigDecimal, any Number (via doubleValue) and parseable Strings; anything else - or an unparseable string - makes coerceOrNull return null and coerce throw this CoercionException.","triggerScenarios":"setParameter('amount', v) where the attribute is BigDecimal and v is neither Number nor String (Boolean, LocalDate, char[], a Value Object); or a String that Double.parseDouble cannot read, e.g. '1.234,56' in a non-US locale, '1_000', '' or a currency symbol.","commonSituations":"Locale-formatted numeric strings from UI/CSV import; passing boxed primitives of unrelated types after a signature change; entity attributes reassigned values of the wrong type in copy/mapper code (MapStruct misconfiguration); native query scalars coerced to BigDecimal.","solutions":["Convert to the correct Java type before setting: new BigDecimal(cleanedString) or valueOf(Number)","Strip formatting (symbols, grouping, spaces) and parse with the value's actual locale before binding","Bind with an explicit type when needed: setParameter(name, value, BigDecimal.class) or the corresponding StandardBasicTypes constant","Add validation at the service boundary so only Number/valid-String reach BigDecimal attributes"],"exampleFix":"// before\nquery.setParameter(\"amount\", \"1.234,56\"); // German-format string -> CoercionException\nquery.setParameter(\"amount\", someBoolean);\n// after\nNumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMANY);\nBigDecimal amount = BigDecimal.valueOf(nf.parse(\"1.234,56\").doubleValue());\nquery.setParameter(\"amount\", amount);","handlingStrategy":"type-guard","validationCode":"// pre-validate anything you feed to a BigDecimal attribute/parameter\nstatic BigDecimal toBigDecimal(Object v) {\n    if (v instanceof BigDecimal bd) return bd;\n    if (v instanceof Number n) return BigDecimal.valueOf(n.doubleValue());\n    if (v instanceof String s && s.matches(\"-?\\\\d+(\\\\.\\\\d+)?\")) return new BigDecimal(s);\n    throw new IllegalArgumentException(\"Not coercible to BigDecimal: \" + v);\n}","typeGuard":"static boolean isCoercibleToBigDecimal(Object v) {\n    return v == null || v instanceof Number\n        || (v instanceof String s && s.matches(\"[+-]?\\\\d+(?:\\\\.\\\\d+)?\"));\n}","tryCatchPattern":"try {\n    query.setParameter(\"amount\", amount);\n} catch (CoercionException e) {\n    // message names the value and class: normalize and retry once\n    BigDecimal fixed = NumberFormat.getInstance(Locale.GERMANY).parse(String.valueOf(amount)) instanceof Number n\n        ? BigDecimal.valueOf(n.doubleValue()) : null;\n    if (fixed != null) query.setParameter(\"amount\", fixed); else throw e;\n}","preventionTips":["Bind Number values, never locale-formatted strings","Validate numeric request parameters at the API boundary (regex/Bean Validation @DecimalMin etc.)","Strip grouping separators and currency symbols before parsing","Watch for Boolean/Date accidentally passed after DTO refactors"],"tags":["hibernate","orm","type-coercion","bigdecimal","query-parameters","number-format"],"backgroundTag":"number-coercion-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}