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

  1. Round explicitly if truncation semantics are agreed: `toShort(Math.round(d))` / `(short) Math.round(d)`; otherwise re-type the attribute as Double/BigDecimal.
  2. Change the column to a decimal type (DECIMAL/DOUBLE) if fractional values must be stored.
  3. Validate whole-number-ness at the boundary before persisting or binding.
  4. 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

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


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