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",
floatValueView on GitHub (pinned to fad1729dce)
Solutions
- 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).
- Round explicitly in your code when truncation is the agreed semantic: `Math.round`, `intValue()` after a whole-number check.
- Store fractional values in DOUBLE/DECIMAL columns instead of INTEGER.
- 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
- Type JSON DTO numeric fields concretely (Integer) instead of Object/Number.
- Do not enable Jackson's ACCEPT_FLOAT_AS_INT globally without agreeing truncation semantics.
- Validate whole-number-ness in the web layer for integer endpoints.
- In HQL, wrap avg()/division results with round() before comparing to integral paths.
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
- Cannot coerce Double value `%s` to Byte : not a whole number
- Cannot coerce Double value `%s` as Short : not a whole numbe
- Unable to coerce Float value `%s` to Integer: not a whole nu
- Unable to coerce Double value `%s` as Integer: not a whole n
- Unable to coerce Double value `%s` as BigInteger: not a whol
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/d9b18a792b720474.
Report an issue: GitHub.