hibernate/hibernate-orm · error · CoercionException

Unable to coerce Float value `%s` to Integer: not a whole nu

Error message

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

What it means

Hibernate throws this CoercionException when a Float with a fractional part is coerced to Integer. CoercionHelper.toInteger(Float) first checks isWholeNumber(floatValue); values like 3.14f fail before any narrowing occurs. It is invoked from IntegerJavaType.coerce when a Float value is assigned to or bound against an Integer-mapped attribute. Hibernate deliberately blocks lossy fractional-to-integral coercion rather than silently truncating.

Source

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

	}

	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
					)
			);
		}

		return toInteger( floatValue.longValue() );
	}

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

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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Round deliberately when truncation is fine: `Math.round(f)` then int assignment; otherwise store as FLOAT/DOUBLE.
  2. Fix producers to emit integral types for count-like fields.
  3. Validate incoming Numbers are whole before mapping onto Integer attributes.
  4. Where a fixed policy exists, centralize it in an AttributeConverter<Float,Integer>.

Example fix

// before
Float progress = reportEngine.completion();  // e.g. 66.6f
report.setProgress(progress);                 // Integer 'progress' -> "not a whole number"

// after
report.setProgress(Math.round(progress));
// or declare progress as Float with a FLOAT column
Defensive patterns

Strategy: validation

Validate before calling

Float f = engine.completion();
if (f != Math.rint(f)) throw new IllegalArgumentException("progress must be whole: " + f);
report.setProgress(Math.round(f));

Type guard

static boolean isWholeFloat(Float f) { return f != null && !f.isNaN() && !f.isInfinite() && f == Math.rint(f); }

Try / catch

catch CoercionException and translate to a validation error naming the field; deterministic — no retry.

Prevention

When it happens

Trigger: `IntegerJavaType.coerce(3.14f)` — e.g. `entity.setQuantity(floatComputedValue)` on an int/Integer attribute, or `setParameter("qty", 2.9f)` against an Integer-typed path; typical with UI components or math APIs returning Float for counts.

Common situations: Slider/progress Float values from UI toolkits persisted into INTEGER columns; float-based math feeding quantity/count fields; legacy Float-typed interfaces; NoSQL or analytics sources yielding floats for integral data.

Related errors


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