hibernate/hibernate-orm · error · IllegalArgumentException
literal value cannot be null
Error message
literal value cannot be null
What it means
criteriaBuilder.literal(null) is a non-standard convenience: by default Hibernate returns an SqmLiteralNull, but when JPA query compliance is enabled (hibernate.jpa.compliance.query=true, or Jakarta persistence compliance settings that imply it) Hibernate enforces the spec, where literal(null) is undefined, and throws IllegalArgumentException. The compliance flag makes Hibernate reject the call instead of silently producing its dialect extension.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java:1963
resolveEnumType( typeConfiguration, enumValue );
}
else {
return result;
}
}
private static <E extends Enum<E>> BasicType<E> resolveEnumType(TypeConfiguration configuration, Enum<E> enumValue) {
final var enumJavaType = new EnumJavaType<>( ReflectHelper.getClass( enumValue ) );
final var jdbcType = enumJavaType.getRecommendedJdbcType( configuration.getCurrentBaseSqlTypeIndicators() );
return configuration.getBasicTypeRegistry().resolve( enumJavaType, jdbcType );
}
@Nonnull
@Override
public <T> SqmLiteral<T> literal(@Nonnull T value) {
if ( value == null ) {
if ( jpaCompliance.isJpaQueryComplianceEnabled() ) {
throw new IllegalArgumentException( "literal value cannot be null" );
}
return new SqmLiteralNull<>( this );
}
else {
return new SqmLiteral<>( value, resolveExpressible( getParameterBindType( value ) ), this );
}
}
@Nonnull
@Override
public <N extends Number & Comparable<N>> SqmNumericExpression<N> numericLiteral(@Nonnull N value) {
return new SqmNumericExpressionWrapper<>( literal( value ) );
}
@Nonnull
@Override
public TextExpression stringLiteral(@Nonnull String value) {
return new SqmTextExpressionWrapper( literal( value ) );View on GitHub (pinned to fad1729dce)
Solutions
- Use the spec-typed null: cb.nullLiteral(String.class) (or the wanted type) instead of cb.literal(null).
- For IS NULL comparisons just call cb.isNull(path)/cb.isNotNull(path) rather than comparing against a null literal.
- Only if you deliberately want Hibernate's lenient behavior: set hibernate.jpa.compliance.query=false and document the deviation.
Example fix
// before
Predicate p = cb.equal(order.get("shippedAt"), cb.literal(maybeNull)); // maybeNull == null + JPA compliance on
// after
Predicate p = maybeNull == null
? cb.isNull(order.get("shippedAt"))
: cb.equal(order.get("shippedAt"), cb.literal(maybeNull));
// or, when a typed null expression is required:
Expression<String> nullExpr = cb.nullLiteral(String.class); Defensive patterns
Strategy: validation
Validate before calling
Expression<T> safeLiteral(CriteriaBuilder cb, T value, Class<T> type) {
return value == null ? cb.nullLiteral(type) : cb.literal(value);
} Try / catch
try {
e = cb.literal(nullable);
} catch (IllegalArgumentException ex) {
if ("literal value cannot be null".equals(ex.getMessage())) e = cb.nullLiteral(expectedType);
else throw ex;
} Prevention
- Never route possibly-null constants through literal(); branch to isNull/isNotNull or nullLiteral(Class).
- Enable hibernate.jpa.compliance.query in tests if you enable it in production, so literal(null) misuse surfaces early.
- Wrap literal creation in one helper (as above) used by all predicate builders.
When it happens
Trigger: cb.literal(someNullableValue) where someNullableValue evaluates to null while hibernate.jpa.jpaComplianceQuery=true (AvailableSettings.JPA_QUERY_COMPLIANCE); test suites that enable full JPA compliance globally (hibernate.jpa.compliance=true) and then build IS NULL predicates via literal(null).
Common situations: Setting jakarta.persistence or hibernate.jpa.compliance properties to true for certification-style strictness and then reusing Hibernate-idiomatic literal(null) code; upgrading apps where compliance defaults changed; generic predicate builders that funnel every constant through literal().
Related errors
- Informix does not support binary literals
- Transaction already active (in JPA compliant mode)
- rollback() called on inactive transaction (in JPA compliant
- setRollbackOnly() called on inactive transaction (in JPA com
- getRollbackOnly() called on inactive transaction (in JPA com
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c7bb8900604a1538.
Report an issue: GitHub.