hibernate/hibernate-orm · error · CoercionException

Cannot coerce Long value `%s` as Short : underflow

Error message

Cannot coerce Long value `%s` as Short : underflow

What it means

Hibernate throws this CoercionException when a Long is narrowed to Short and falls below -32768. It originates in CoercionHelper.toShort(Long), invoked by ShortJavaType.coerce when a Long value is coerced for a Short-mapped attribute. Together with its overflow sibling it enforces Hibernate 6's no-lossy-narrowing policy; the message names the exact value that failed.

Source

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

	public static Short toShort(Integer value) {
		if ( value > Short.MAX_VALUE ) {
			throw new CoercionException( "Cannot coerce Integer value `" + value + "` as Short : overflow" );
		}

		if ( value < Short.MIN_VALUE ) {
			throw new CoercionException( "Cannot coerce Integer value `" + value + "` as Short : underflow" );
		}

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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Re-type attribute/column (Short -> Long/Integer, SMALLINT -> INT/BIGINT) to match real magnitudes.
  2. Range-check and narrow explicitly: `-32768 <= v <= 32767` then `(short) v`.
  3. Fix upstream sign/unit bugs that inflate magnitudes beyond the short domain.
  4. Validate Long inputs against the short range at the API/import boundary.

Example fix

// before
long delta = oldBalance - newBalance;  // e.g. -150000
account.setBalanceDelta(delta);        // Short field -> underflow

// after
if (delta < Short.MIN_VALUE || delta > Short.MAX_VALUE) {
    throw new IllegalArgumentException("balance delta out of short range: " + delta);
}
account.setBalanceDelta((short) delta);
// or widen balanceDelta to Long
Defensive patterns

Strategy: validation

Validate before calling

if (delta < Short.MIN_VALUE || delta > Short.MAX_VALUE) {
    throw new IllegalArgumentException("delta out of short range: " + delta);
}
account.setBalanceDelta((short) delta);

Type guard

static boolean fitsInShort(long v) { return v >= -32768L && v <= 32767L; }

Try / catch

catch CoercionException around merge/persist; surface as business-rule violation, never swallow silently.

Prevention

When it happens

Trigger: Assigning a Long < -32768 (e.g. -100000L) to a Short/short entity attribute via a loosely typed setter, or binding it as a query parameter to a Short-typed path; e.g. `account.setBalanceDelta(-100000L)` with balanceDelta mapped from SMALLINT.

Common situations: Long-typed deltas in financial or telemetry pipelines stored into SMALLINT fields; negative sentinels or error codes as Long constants; Hibernate 5 -> 6 upgrades where the same write used to truncate to a wrong-but-silent value; dynamic Map-based entity models with Long values.

Related errors


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