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

  1. Write the literal in the converter's domain type (the Java attribute type), not the column type
  2. Replace the literal with a bound parameter: setParameter works through the converter and avoids literal conversion
  3. Widen the converter's relational Java type to accept the literal form, or register a JavaType coercion
  4. 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

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


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