hibernate/hibernate-orm · error · CoercionException

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

Error message

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

What it means

Hibernate throws this CoercionException when a Double with a fractional part must be coerced to Integer. CoercionHelper.toInteger(Double) rejects non-whole values via isWholeNumber before converting through the Long path. It is reached from IntegerJavaType.coerce when a Double value is supplied to an Integer-mapped attribute — the most commonly hit case of the family, since so many pipelines hand back Double for numeric data.

Source

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

	public static Short toShort(BigDecimal value) {
		return coerceWrappingError( value::shortValueExact );
	}

	public static Integer toInteger(Byte value) {
		return value.intValue();
	}

	public static Integer toInteger(Short value) {
		return value.intValue();
	}

	public static Integer toInteger(Long value) {
		return coerceWrappingError( () -> Math.toIntExact( value ) );
	}

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

		return toInteger( doubleValue.longValue() );
	}

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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Fix the producer/consumer types: make DTO fields Integer, or configure the deserializer (e.g. Jackson `ACCEPT_FLOAT_AS_INT` is disabled by default — enable it only if truncation is acceptable, better: fix payloads).
  2. Round explicitly in your code when truncation is the agreed semantic: `Math.round`, `intValue()` after a whole-number check.
  3. Store fractional values in DOUBLE/DECIMAL columns instead of INTEGER.
  4. Validate whole-number-ness of incoming Numbers at the API boundary before mapping onto entities.

Example fix

// before
Map<String,Object> dto = jsonParser.parse(payload); // price: 19.99 as Double
order.setUnits(dto.get("units"));                  // Integer 'units' -> "not a whole number"

// after
Object raw = dto.get("units");
if (raw instanceof Double d && d != Math.rint(d)) throw new IllegalArgumentException("units must be whole: " + d);
order.setUnits(((Number) raw).intValue());
// or fix the API contract to send integers
Defensive patterns

Strategy: validation

Validate before calling

Object raw = payload.get("units");
if (raw instanceof Double d && d != Math.rint(d)) {
    throw new IllegalArgumentException("units must be a whole number: " + d);
}
order.setUnits(((Number) raw).intValue());

Type guard

static boolean isWholeDouble(Object o) { return o instanceof Double d && d == Math.rint(d) && !d.isNaN(); }

Try / catch

try { session.persist(order); } catch (CoercionException e) { throw new BadRequestException("whole-number field received fraction: " + e.getMessage(), e); }

Prevention

When it happens

Trigger: `IntegerJavaType.coerce(2.75)` — assigning a Double to an Integer/int entity field through a Number/Object-typed setter, `setParameter("n", 10.5)` bound against an Integer path, or HQL/Criteria arithmetic (`avg(...)`, `/` division) yielding Double results assigned/compared into INTEGER-mapped attributes.

Common situations: JSON APIs (Jackson/Gson) deserializing numeric fields as Double into DTOs copied onto Integer entity fields; computed averages or ratios stored into INT columns; JavaScript/Node frontends sending floats for integer fields; Elasticsearch/NoSQL sources returning all numbers as doubles; refactor of a Double attribute to Integer while old data or writers still emit fractions.

Related errors


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