hibernate/hibernate-orm · error · CoercionException
Unable to coerce value [%s (%s)] to BigDecimal
Error message
Unable to coerce value [%s (%s)] to BigDecimal
What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BigDecimalJavaType.java:141
@Override
public long getDefaultSqlLength(Dialect dialect, JdbcType jdbcType) {
return getDefaultSqlPrecision( dialect, jdbcType ) + 2;
}
@Override
public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {
return dialect.getDefaultDecimalPrecision();
}
@Override
public @Nullable BigDecimal coerce(@Nullable Object value) {
if ( value == null ) {
return null;
}
final var coerced = coerceOrNull( value );
if ( coerced == null ) {
throw new CoercionException(
String.format(
Locale.ROOT,
"Unable to coerce value [%s (%s)] to BigDecimal",
value,
value.getClass().getName()
)
);
}
return coerced;
}
@Override
public @Nullable BigDecimal coerceOrNull(@Nonnull Object value) {
if ( value instanceof BigDecimal bigDecimal ) {
return bigDecimal;
}
if ( value instanceof Number number ) {View on GitHub (pinned to fad1729dce)
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
Example fix
// before
query.setParameter("amount", "1.234,56"); // German-format string -> CoercionException
query.setParameter("amount", someBoolean);
// after
NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMANY);
BigDecimal amount = BigDecimal.valueOf(nf.parse("1.234,56").doubleValue());
query.setParameter("amount", amount); Defensive patterns
Strategy: type-guard
Validate before calling
// pre-validate anything you feed to a BigDecimal attribute/parameter
static BigDecimal toBigDecimal(Object v) {
if (v instanceof BigDecimal bd) return bd;
if (v instanceof Number n) return BigDecimal.valueOf(n.doubleValue());
if (v instanceof String s && s.matches("-?\\d+(\\.\\d+)?")) return new BigDecimal(s);
throw new IllegalArgumentException("Not coercible to BigDecimal: " + v);
} Type guard
static boolean isCoercibleToBigDecimal(Object v) {
return v == null || v instanceof Number
|| (v instanceof String s && s.matches("[+-]?\\d+(?:\\.\\d+)?"));
} Try / catch
try {
query.setParameter("amount", amount);
} catch (CoercionException e) {
// message names the value and class: normalize and retry once
BigDecimal fixed = NumberFormat.getInstance(Locale.GERMANY).parse(String.valueOf(amount)) instanceof Number n
? BigDecimal.valueOf(n.doubleValue()) : null;
if (fixed != null) query.setParameter("amount", fixed); else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to coerce value [%s (%s)] to BigInteger
- Unable to determine JDBC type for converted parameter relati
- Unknown unwrap conversion requested: " + type.getTypeName()
- Named query definition is null
- Named query definition name is null: %s
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/d7204b50a2ab857e.
Report an issue: GitHub.