hibernate/hibernate-orm · error · CoercionException
Cannot coerce Integer value `%s` to Byte : underflow
Error message
Cannot coerce Integer value `%s` to Byte : underflow
What it means
Hibernate throws this CoercionException (a HibernateException subclass) when a Java Integer value must be narrowed to java.lang.Byte (range -128..127) and the value is below -128. It is thrown from CoercionHelper.toByte(Integer), reached via ByteJavaType.coerce(...) during persist/merge/saveOrUpdate or query-parameter binding when the value handed to a Byte-mapped attribute is an Integer that cannot be represented as a byte. Unlike silent Java narrowing casts, Hibernate 6 refuses lossy conversions and fails fast with the offending value in the message (the `%s` is the input value).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java:58
);
}
return value.byteValue();
}
public static Byte toByte(Integer value) {
if ( value > Byte.MAX_VALUE ) {
throw new CoercionException(
String.format(
Locale.ROOT,
"Cannot coerce Integer value `%s` to Byte : overflow",
value
)
);
}
if ( value < Byte.MIN_VALUE ) {
throw new CoercionException(
String.format(
Locale.ROOT,
"Cannot coerce Integer value `%s` to Byte : underflow",
value
)
);
}
return value.byteValue();
}
public static Byte toByte(Long value) {
if ( value > Byte.MAX_VALUE ) {
throw new CoercionException(
String.format(
Locale.ROOT,
"Cannot coerce Long value `%s` to Byte : overflow",
valueView on GitHub (pinned to fad1729dce)
Solutions
- Fix the type mismatch at the source: either declare the entity attribute as Integer/Short to match the real value domain, or convert the value to byte before assignment (`(byte) intValue` or `intValue.byteValue()` after a range check).
- If narrowing is intentional and out-of-range data is impossible-by-contract, add an explicit javax.persistence.AttributeConverter<Integer,Byte> that documents and performs the narrowing.
- If out-of-range values are legitimate, change the column DDL (e.g. TINYINT -> SMALLINT/INT) and remap the attribute type accordingly.
- Add a range guard (-128..127) in the setter or at the import boundary and reject/clamp bad values before they reach the Session.
Example fix
// before
@Entity class Meter {
Byte offset; // tinyint column
}
meter.setOffset(payloadValue); // payloadValue is Integer -200 -> CoercionException
// after
@Entity class Meter {
Integer offset; // matches actual value domain
}
// or guard before assignment:
if (payloadValue >= Byte.MIN_VALUE && payloadValue <= Byte.MAX_VALUE) {
meter.setOffset(payloadValue.byteValue());
} else {
throw new IllegalArgumentException("offset out of byte range: " + payloadValue);
} Defensive patterns
Strategy: validation
Validate before calling
Integer v = payload.getByteField();
if (v < Byte.MIN_VALUE || v > Byte.MAX_VALUE) {
throw new IllegalArgumentException("value out of byte range: " + v);
}
entity.setByteField(v.byteValue()); Type guard
static boolean fitsInByte(Integer v) { return v != null && v >= Byte.MIN_VALUE && v <= Byte.MAX_VALUE; } Try / catch
try { session.merge(entity); } catch (CoercionException e) { /* log offending value, reject the write */ } // CoercionException extends HibernateException Prevention
- Declare entity numeric attributes with the exact Java type the writers use; avoid Number/Object-typed setters for small integer fields.
- Validate numeric ranges at the API/import boundary before values reach the Session.
- When mapping tinyint columns, confirm no unsigned values > 127 can occur, or map to Short/Integer.
- Add integration tests that persist edge values (-129, -128, 127, 128) against narrowed attributes.
When it happens
Trigger: Entity attribute declared `Byte`/`byte` (e.g. a tinyint column) but the code assigns an Integer below -128: `entity.setByteValue(-200)` where the setter takes Number/Object, or `session.createQuery(...).setParameter("b", -200)` bound against a Byte-typed path. Also fires when a Map<String,Object> payload or dynamic-model value containing an Integer is funneled into a Byte attribute via ByteJavaType.coerce.
Common situations: JSON payloads deserialized by Jackson into Integer/Object fields then copied onto a Byte entity property; dynamic maps or CSV import feeds; switching an attribute from Integer to Byte without cleaning stored data; moving from Hibernate 5 (which narrowed silently) to Hibernate 6 (which validates); unsigned TINYINT columns on MySQL/MariaDB holding values 128..255 that map to negative/oversized integers.
Related errors
- Cannot coerce Long value `%s` to Byte : underflow
- Cannot coerce Long value `%s` to Byte : overflow
- Cannot coerce Double value `%s` to Byte : underflow
- Cannot coerce Float value `%s` to Byte : underflow
- Cannot coerce Integer value `%s` as Short : underflow
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a8555bd2e43ccdd1.
Report an issue: GitHub.