hibernate/hibernate-orm · error · CoercionException

Unable to coerce Double value `%s` as Integer: not a whole n

Error message

Unable to coerce Double value `%s` as Integer: not a whole number

What it means

Hibernate throws this CoercionException when a Double with a fractional part is coerced to Long. Note the message text is misleading: CoercionHelper.toLong(Double) says "as Integer" although the target type is Long — a copy-paste slip in Hibernate itself, so grep for toLong(LongJavaType) semantics, not Integer, when debugging. The check itself (isWholeNumber) is correct and fires from LongJavaType.coerce when a fractional Double reaches a Long-mapped attribute.

Source

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

	public static Integer toInteger(BigDecimal value) {
		return coerceWrappingError( value::intValueExact );
	}

	public static Long toLong(Byte value) {
		return value.longValue();
	}

	public static Long toLong(Short value) {
		return value.longValue();
	}

	public static Long toLong(Integer value) {
		return value.longValue();
	}

	public static Long toLong(Double doubleValue) {
		if ( ! isWholeNumber( doubleValue ) ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Unable to coerce Double value `%s` as Integer: not a whole number",
							doubleValue
					)
			);
		}
		return doubleValue.longValue();
	}

	public static Long toLong(Float floatValue) {
		if ( ! isWholeNumber( floatValue ) ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Unable to coerce Float value `%s` as Integer: not a whole number",
							floatValue
					)

View on GitHub (pinned to fad1729dce)

Solutions

  1. Fix the payload/producer: send integral JSON numbers and type DTO fields as Long, or convert explicitly with a whole-number check plus `longValue()`.
  2. Round when truncation is agreed: `Math.round(d)` before assigning to the Long field.
  3. Store fractional data in DOUBLE/DECIMAL columns instead of BIGINT.
  4. When reading this error, remember the message says Integer but the failing conversion is Double -> Long (known Hibernate message bug).

Example fix

// before
Object rawId = jsonMap.get("orderId");   // Double 922337203685477580.5 style values or 123.45
order.setExternalRef(rawId);             // Long field -> CoercionException (misleadingly says "as Integer")

// after
Double d = (Double) rawId;
if (d != Math.rint(d)) throw new IllegalArgumentException("id must be whole: " + d);
order.setExternalRef(d.longValue());
// better: type the DTO field as Long so Jackson deserializes integrally
Defensive patterns

Strategy: validation

Validate before calling

Object raw = json.get("orderId");
if (raw instanceof Double d) {
    if (d != Math.rint(d)) throw new IllegalArgumentException("id must be whole: " + d);
    entity.setExternalRef(d.longValue());
} else {
    entity.setExternalRef(((Number) raw).longValue());
}

Type guard

static boolean isWholeDoubleForLong(Double d) { return d != null && d == Math.rint(d) && Math.abs(d) < 9.007199254740992E15; } // also guards 2^53 precision limit

Try / catch

catch CoercionException; note the message wrongly says "as Integer" — match on stack trace (LongJavaType/CoercionHelper.toLong) when routing the error.

Prevention

When it happens

Trigger: `LongJavaType.coerce(1.5)` — assigning a Double to a Long/long entity field (IDs, counts, timestamps) via a Number/Object-typed setter, or `setParameter("id", 123.45)` against a Long-typed path; e.g. a JSON id field deserialized as Double then set on a Long id-like attribute.

Common situations: JavaScript-produced JSON where all numbers parse as Double on the Java side and get copied onto Long fields (ids, epoch millis); Jackson/Gson loosely typed maps feeding Long attributes; analytics pipelines returning doubles for counts; developers confused by the "Integer" wording in the message when the real mismatch is Long.

Related errors


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