hibernate/hibernate-orm · error · CoercionException
Cannot coerce Double value `%s` as Short : not a whole numbe
Error message
Cannot coerce Double value `%s` as Short : not a whole number
What it means
Hibernate throws this CoercionException when a Double with a fractional part must be coerced to Short. CoercionHelper.toShort(Double) first rejects non-whole values via isWholeNumber before delegating to the Long-based narrowing path. It is reached from ShortJavaType.coerce when a Double value is assigned to or bound against a Short-mapped attribute. Hibernate refuses lossy fractional-to-integral conversion instead of truncating toward zero.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java:200
return value.shortValue();
}
public static Short toShort(Long value) {
if ( value > Short.MAX_VALUE ) {
throw new CoercionException( "Cannot coerce Long value `" + value + "` as Short : overflow" );
}
if ( value < Short.MIN_VALUE ) {
throw new CoercionException( "Cannot coerce Long value `" + value + "` as Short : underflow" );
}
return value.shortValue();
}
public static Short toShort(Double doubleValue) {
if ( ! isWholeNumber( doubleValue ) ) {
throw new CoercionException( "Cannot coerce Double value `" + doubleValue + "` as Short : not a whole number" );
}
return toShort( doubleValue.longValue() );
}
public static Short toShort(Float floatValue) {
if ( ! isWholeNumber( floatValue ) ) {
throw new CoercionException( "Cannot coerce Float value `" + floatValue + "` as Short : not a whole number" );
}
return toShort( floatValue.longValue() );
}
public static Short toShort(BigInteger value) {
return coerceWrappingError( value::shortValueExact );
}
public static Short toShort(BigDecimal value) {
return coerceWrappingError( value::shortValueExact );
}View on GitHub (pinned to fad1729dce)
Solutions
- Round explicitly if truncation semantics are agreed: `toShort(Math.round(d))` / `(short) Math.round(d)`; otherwise re-type the attribute as Double/BigDecimal.
- Change the column to a decimal type (DECIMAL/DOUBLE) if fractional values must be stored.
- Validate whole-number-ness at the boundary before persisting or binding.
- Fix HQL/Criteria expressions feeding Short paths: apply round()/floor() in the query or compute in Java before assignment.
Example fix
// before Double avgOrder = orders.stream().mapToDouble(o -> o.total).average().orElse(0); customer.setAvgOrder(avgOrder); // Short field -> "not a whole number" // after customer.setAvgOrder((short) Math.round(avgOrder)); // or declare avgOrder as Double with a DOUBLE column
Defensive patterns
Strategy: validation
Validate before calling
Double d = computed;
if (d != Math.rint(d)) throw new IllegalArgumentException("must be whole: " + d);
entity.setCode(d.longValue() == (long) d.doubleValue() ? (short) d.longValue() : null); // plus range check Type guard
static boolean isWholeNumber(Double d) { return d != null && d == Math.rint(d) && !d.isNaN(); } Try / catch
catch CoercionException and translate into an explicit rounding policy decision; do not blanket-catch and drop values.
Prevention
- Pick one place to round aggregates (avg/sum division) before storing into SMALLINT.
- Prefer storing raw averages in DOUBLE and deriving integral views in queries.
- Watch HQL integer division: use `cast(... as int)` or round() when feeding Short paths.
When it happens
Trigger: `ShortJavaType.coerce(2.5)` — e.g. `entity.setDiscount(12.75)` on a Short/short attribute, `setParameter("s", 99.9)` against a Short-typed path, or HQL arithmetic like `avg(...)` or `/` producing Double results piped into a SMALLINT-mapped field.
Common situations: Percentage/discount values computed as Double but stored in SMALLINT columns; Jackson-deserialized decimal JSON numbers landing on Short DTO fields; report aggregations (averages) written back into integral columns; refactor from Double to Short attribute while producers still emit fractions.
Related errors
- Cannot coerce Double value `%s` to Byte : not a whole number
- Cannot coerce Float value `%s` as Short : not a whole number
- Unable to coerce Double value `%s` to Integer: not a whole n
- 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/fba7ba43cb575253.
Report an issue: GitHub.