hibernate/hibernate-orm · error · PersistenceException

Error attempting to apply AttributeConverter

Error message

Error attempting to apply AttributeConverter

What it means

Hibernate wraps any non-PersistenceException RuntimeException thrown by your jakarta.persistence.AttributeConverter.convertToEntityAttribute while materializing an entity attribute from the database value. This variant is thrown from AttributeConverterBean, the wrapper used when the converter is resolved as a managed bean (CDI/Spring). The original exception is preserved as the cause, so the real failure is one level down.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/AttributeConverterBean.java:103

				? new AttributeConverterMutabilityPlan<>( this, true )
				: (MutabilityPlan<O>) mutabilityPlan;
	}

	@Override
	public ManagedBean<? extends AttributeConverter<O, R>> getConverterBean() {
		return attributeConverterBean;
	}

	@Override
	public O toDomainValue(R relationalForm) {
		try {
			return attributeConverterBean.getBeanInstance().convertToEntityAttribute( relationalForm );
		}
		catch (PersistenceException pe) {
			throw pe;
		}
		catch (RuntimeException re) {
			throw new PersistenceException( "Error attempting to apply AttributeConverter", re );
		}
	}

	@Override
	public R toRelationalValue(O domainForm) {
		try {
			return attributeConverterBean.getBeanInstance().convertToDatabaseColumn( domainForm );
		}
		catch (PersistenceException pe) {
			throw pe;
		}
		catch (RuntimeException re) {
			throw new PersistenceException( "Error attempting to apply AttributeConverter: " + re.getMessage(), re );
		}
	}

	@Override
	public JavaType<? extends AttributeConverter<O, R>> getConverterJavaType() {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Read the cause: catch PersistenceException and inspect getCause() to find the converter line that failed
  2. Make convertToEntityAttribute defensive: handle null input and unknown values explicitly (return null, throw an informative exception, or map to a default)
  3. Cleanse or migrate offending column data so every stored value is convertible
  4. If the JDBC type changed, fix the converter's declared relational type to match what the driver actually returns

Example fix

// before
@Override
public Status convertToEntityAttribute(String dbValue) {
    return Status.valueOf(dbValue); // throws on null/unknown code
}
// after
@Override
public Status convertToEntityAttribute(String dbValue) {
    if (dbValue == null || dbValue.isBlank()) {
        return null;
    }
    try {
        return Status.valueOf(dbValue);
    }
    catch (IllegalArgumentException e) {
        throw new IllegalStateException("Unknown status code in DB: " + dbValue, e);
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before loading: sanity-check known raw values if you control the query
List<String> bad = jdbcTemplate.queryForList("select distinct status from t_order", String.class)
        .stream().filter(v -> v != null && Status.tryParse(v) == null).toList();
if (!bad.isEmpty()) throw new IllegalStateException("Unconvertible codes: " + bad);

Type guard

// guard the converter itself against unexpected input
static Status safeParse(String dbValue) {
    if (dbValue == null) return null;
    try { return Status.valueOf(dbValue); }
    catch (IllegalArgumentException e) { return null; }
}

Try / catch

try {
    Order order = session.find(Order.class, id);
} catch (PersistenceException e) {
    if (e.getCause() instanceof IllegalArgumentException iae) {
        // converter rejected a stored value: log column + value, quarantine row
        log.warn("Unconvertible stored value: {}", iae.getMessage());
    } else { throw e; }
}

Prevention

When it happens

Trigger: An entity attribute annotated @Convert (or covered by an auto-applied @Converter) whose converter class is obtained through the bean manager; loading the entity, and convertToEntityAttribute(relationalForm) throws a RuntimeException (NPE on null column, NumberFormatException on dirty data, IllegalArgumentException on an unrecognized code).

Common situations: Legacy rows containing values the converter cannot parse (old enum codes, empty strings, nulls not guarded); a schema/driver change making the JDBC value arrive as a different type (Integer vs String); migrating to Hibernate 6/7 where converter type checking became stricter; converter relying on injected beans that are null in the Hibernate module path.

Related errors


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