hibernate/hibernate-orm · error · CoercionException

Unable to coerce value [%s (%s)] to BigInteger

Error message

Unable to coerce value [%s (%s)] to BigInteger

What it means

BigIntegerJavaType.coerce applies Hibernate's implicit coercion toward java.math.BigInteger for mismatched values. coerceOrNull accepts BigInteger, any Number and parseable Strings; every other type, or a String that cannot be parsed as a double, results in this CoercionException naming the offending value and its class.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BigIntegerJavaType.java:143

	@Override
	public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {
		return dialect.getDefaultDecimalPrecision();
	}

	@Override
	public int getDefaultSqlScale(Dialect dialect, JdbcType jdbcType) {
		return 0;
	}

	@Override
	public @Nullable BigInteger coerce(@Nullable Object value) {
		if ( value == null ) {
			return null;
		}
		final var coerced = coerceOrNull( value );
		if ( coerced == null ) {
			throw new CoercionException(
					String.format(
							Locale.ROOT,
							"Unable to coerce value [%s (%s)] to BigInteger",
							value,
							value.getClass().getName()
					)
			);
		}
		return coerced;
	}

	@Override
	public @Nullable BigInteger coerceOrNull(@Nonnull Object value) {
		if ( value instanceof BigInteger bigInteger ) {
			return bigInteger;
		}

		if ( value instanceof Byte byteValue ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Parse to BigInteger before binding, using the value's real locale and stripping grouping separators
  2. Pass Number instances (long/Long is safest for IDs) instead of formatted text
  3. Validate/normalize incoming strings at the API boundary (regex or NumberFormat.parse)
  4. Check the value's class named in the message to find the offending caller

Example fix

// before
query.setParameter("userId", "1.000.000"); // grouping separators -> CoercionException
// after
String digits = "1.000.000".replaceAll("[^0-9]", "");
query.setParameter("userId", new BigInteger(digits));
Defensive patterns

Strategy: type-guard

Validate before calling

static BigInteger toBigInteger(Object v) {
    if (v instanceof BigInteger bi) return bi;
    if (v instanceof Number n) return BigInteger.valueOf(n.longValue());
    if (v instanceof String s) return new BigInteger(s.replaceAll("[^\\d-]", ""));
    throw new IllegalArgumentException("Not coercible to BigInteger: " + v);
}

Type guard

static boolean isCoercibleToBigInteger(Object v) {
    return v == null || v instanceof Number
        || (v instanceof String s && s.matches("[+-]?\\d+"));
}

Try / catch

try {
    query.setParameter("userId", idValue);
} catch (CoercionException e) {
    if (idValue instanceof String s && s.matches("\\d+")) {
        query.setParameter("userId", new BigInteger(s)); // digits only: retry clean
    } else throw e;
}

Prevention

When it happens

Trigger: Binding or assigning a value to a BigInteger attribute/parameter that is neither Number nor String (Boolean, enum, date), or a locale/formatted string like '1.000' (grouping) or '12ab' that Double.parseDouble rejects.

Common situations: IDs read from requests as formatted strings; grouping separators from European locales; passing a char[] or StringBuilder; converting DTO fields with mismatched types in mapper code; upgrade to Hibernate 6 where coercion replaced silent legacy behavior.

Related errors


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