hibernate/hibernate-orm · error · CoercionException

Cannot coerce Float value `%s` to Byte : not a whole number

Error message

Cannot coerce Float value `%s` to Byte : not a whole number

What it means

Hibernate throws this CoercionException when a Float with a fractional part is coerced to Byte. CoercionHelper.toByte(Float) runs isWholeNumber(value) first; values like 2.5f fail immediately. It is invoked from ByteJavaType.coerce when a Float value reaches a Byte-mapped attribute during persist/merge or parameter binding. Hibernate refuses lossy fractional-to-integral conversion rather than truncating.

Source

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

			);
		}

		if ( value < Byte.MIN_VALUE ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Cannot coerce Double value `%s` to Byte : underflow",
							value
					)
			);
		}

		return value.byteValue();
	}

	public static Byte toByte(Float value) {
		if ( ! isWholeNumber( value ) ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Cannot coerce Float value `%s` to Byte : not a whole number",
							value
					)
			);
		}

		if ( value > Byte.MAX_VALUE ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Cannot coerce Float value `%s` to Byte : overflow",
							value
					)
			);
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Round and narrow explicitly when truncation is fine: `(byte) Math.round(f)` after a range check; otherwise change the attribute type to Float.
  2. Fix the producer to emit integral types (Integer/Byte) for integral fields.
  3. Validate incoming Numbers at the boundary: whole-number plus range checks before Session calls.
  4. Consider an AttributeConverter<Float,Byte> to centralize rounding policy.

Example fix

// before
float progress = uiSlider.getValue();   // e.g. 2.5f
job.setProgress(progress);              // Byte 'progress' -> "not a whole number"

// after
job.setProgress((byte) Math.round(progress));
// or declare progress as Float if fractional progress is meaningful
Defensive patterns

Strategy: validation

Validate before calling

Float f = uiValue;
if (f != Math.rint(f)) throw new IllegalArgumentException("value must be whole: " + f);
if (f < Byte.MIN_VALUE || f > Byte.MAX_VALUE) throw new IllegalArgumentException("out of byte range: " + f);
entity.setCode((byte) (int) f);

Type guard

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

Try / catch

catch CoercionException at the service boundary and translate to a 400 with the field name; deterministic — never retry.

Prevention

When it happens

Trigger: `ByteJavaType.coerce(2.5f)` — assigning a Float literal or computed float to a Byte/byte entity property, or `setParameter("b", 1.1f)` against a Byte path; typical when math libraries or UI layers hand back Floats for integral code fields.

Common situations: Android/Swing UI sliders returning Float progress into tinyint Byte fields; float-based math (weights 0.5f multipliers) feeding code columns; legacy APIs typed as Float; refactor of an attribute from Float to Byte while call sites still pass floats.

Related errors


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