hibernate/hibernate-orm · error · SemanticException
Literal type '%s' did not match domain type '%s' nor convert
Error message
Literal type '%s' did not match domain type '%s' nor converted type '%s'
What it means
While converting a literal to its relational value, the literal's Java class matched neither the domain Java type nor the relational Java type of the value converter in play. The converter only tolerates two special cases - a 1-char CharSequence against a Character relational type, and Number-to-Number coercion - so everything else is rejected as a SemanticException naming all three mismatched types.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java:6235
// For converted query literals, we support both, the domain and relational java type
if ( value == null || valueConverter.getDomainJavaType().isInstance( value ) ) {
return toRelationalValue( valueConverter, value );
}
else if ( valueConverter.getRelationalJavaType().isInstance( value ) ) {
return value;
}
else if ( Character.class.isAssignableFrom( valueConverter.getRelationalJavaType().getJavaTypeClass() )
&& value instanceof CharSequence charSequence && charSequence.length() == 1 ) {
return charSequence.charAt( 0 );
}
// In HQL, number literals might not match the relational java type exactly,
// so we allow coercion between the number types
else if ( Number.class.isAssignableFrom( valueConverter.getRelationalJavaType().getJavaTypeClass() )
&& value instanceof Number ) {
return valueConverter.getRelationalJavaType().coerce( value );
}
else {
throw new SemanticException(
String.format(
Locale.ROOT,
"Literal type '%s' did not match domain type '%s' nor converted type '%s'",
value.getClass(),
valueConverter.getDomainJavaType().getJavaTypeClass().getName(),
valueConverter.getRelationalJavaType().getJavaTypeClass().getName()
)
);
}
}
private static <D> Object toRelationalValue(BasicValueConverter<D, ?> valueConverter, Object value) {
return valueConverter.toRelationalValue( valueConverter.getDomainJavaType().cast( value ) );
}
private <E> EntityTypeLiteral entityTypeLiteral(SqmLiteral<E> literal, DiscriminatorMapping inferableExpressible) {
final E literalValue = literal.getLiteralValue();
final var entityDescriptor =View on GitHub (pinned to fad1729dce)
Solutions
- Write the literal in the converter's domain type (the Java attribute type), not the column type
- Replace the literal with a bound parameter: setParameter works through the converter and avoids literal conversion
- Widen the converter's relational Java type to accept the literal form, or register a JavaType coercion
- If the types truly match and it still throws, check for a broken JavaType.resolve/coerce override in a custom type
Example fix
// before: status stored as int via EnumConverter (domain Status, relational Integer)
select p from P p where p.status = 1
// after: literal in domain type, or use a parameter
select p from P p where p.status = :st // query.setParameter("st", Status.ACTIVE) Defensive patterns
Strategy: validation
Validate before calling
// Before binding HQL literals for converted attributes: check the literal class against the domain type
Object literal = ...;
Class<?> domainType = sessionFactory.getMetamodel()
.entity(E.class).getAttribute("status").getJavaType();
if (!domainType.isInstance(literal)) {
throw new IllegalArgumentException("Literal " + literal.getClass() + " does not match domain type " + domainType);
} Try / catch
try {
return session.createQuery(hql).getResultList();
} catch (org.hibernate.query.SemanticException e) {
log.error("Literal/converter mismatch in {}: {}", hql, e.getMessage());
// switch the offending literal to a typed parameter and retry once
throw e;
} Prevention
- Write literals in the Java attribute type, never the column type
- Prefer parameters over literals for every converted attribute
- Test each AttributeConverter with a query containing a literal of its domain type
When it happens
Trigger: HQL like 'where e.converted = 123' where the attribute's AttributeConverter has domain type String (relational Integer) and the literal is written as the relational type; enum literals against converters with unusual domain types; comparing an attribute whose converter uses a boxed custom value type with a plain Java literal.
Common situations: Custom BasicConverter/AttributeConverter implementations with asymmetric domain/relational types (e.g. enum-to-code, String-to-int); writing query literals by looking at the DB column type instead of the Java attribute type; version upgrades that tightened literal coercion checks.
Related errors
- Parameter %d of function '%s()' has type '%s', but argument
- Start and stop parameters of function '%s()' must be of the
- Step parameter of function '%s()' is of type '%s', but must
- Step parameter of function '%s()' is of type '%s', but must
- Incorrect query result type: query produces '%s' but type '%
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/aa0fb70b401c6173.
Report an issue: GitHub.