hibernate/hibernate-orm · error · CoercionException

Cannot coerce Float value `%s` to Double : underflow

Error message

Cannot coerce Float value `%s` to Double : underflow

What it means

Thrown by CoercionHelper.toDouble(Float) when floatValue < (float) Double.MIN_VALUE. Double.MIN_VALUE is the smallest positive double (~4.9e-324) and casting it to float yields 0.0f, so the condition degenerates to 'floatValue < 0.0f': in this Hibernate version every negative Float fails Float-to-Double widening with 'underflow', even though all negative floats fit comfortably in a double. This is a bug in the guard, not a genuine range problem with your data.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java:356

	}

	public static BigInteger toBigInteger(BigDecimal value) {
		return coerceWrappingError( value::toBigIntegerExact );
	}

	public static Double toDouble(Float floatValue) {
		if ( floatValue > (float) Double.MAX_VALUE ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Cannot coerce Float value `%s` to Double : overflow",
							floatValue
					)
			);
		}

		if ( floatValue < (float) Double.MIN_VALUE ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Cannot coerce Float value `%s` to Double : underflow",
							floatValue
					)
			);
		}

		return (double) floatValue;
	}

	public static Double toDouble(BigInteger value) {
		return coerceWrappingError( value::doubleValue );
	}

	public static Double toDouble(BigDecimal value) {
		return coerceWrappingError( value::doubleValue );
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Widen the value yourself before Hibernate sees it: pass Double.valueOf(f) or (double) f instead of the Float
  2. Change float fields, variables, and parameters to double so the Float overload is never exercised
  3. Upgrade hibernate-core to a release where the negative-float underflow check is corrected
  4. Interim workaround: catch CoercionException and re-coerce from the original value

Example fix

// before
query.setParameter("amount", -1.5f); // Float -> CoercionException: underflow

// after
query.setParameter("amount", -1.5); // double literal, Float coercion path avoided
Defensive patterns

Strategy: type-guard

Validate before calling

// pre-widen every Float before Hibernate sees it
static Object widenFloats(Object v) {
    return v instanceof Float f ? f.doubleValue() : v;
}

Type guard

static boolean safeForDoubleCoercion(Object v) {
    // on affected versions every negative Float trips the underflow guard
    return !(v instanceof Float f) || !(f < 0f);
}

Try / catch

try {
    return query.getSingleResult();
} catch (CoercionException e) {
    if (e.getMessage().contains("underflow") && original instanceof Float f) {
        return rebind(f.doubleValue()); // widen and retry once
    }
    throw e;
}

Prevention

When it happens

Trigger: Binding any negative Float where a double is expected: query.setParameter("delta", -1.5f) on a Double-typed attribute or path; an AttributeConverter or HQL coercion path that feeds a boxed Float into CoercionHelper.toDouble(Float).

Common situations: Entity fields typed Double receiving float literals (the f suffix) or Float values from older APIs; codebases mixing float and double after a schema or entity refactor; failures that appear after upgrading to Hibernate 6.x coercion-based binding.

Related errors


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