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

  1. Convert to the correct Java type before setting: new BigDecimal(cleanedString) or valueOf(Number)
  2. Strip formatting (symbols, grouping, spaces) and parse with the value's actual locale before binding
  3. Bind with an explicit type when needed: setParameter(name, value, BigDecimal.class) or the corresponding StandardBasicTypes constant
  4. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/d7204b50a2ab857e. Report an issue: GitHub.