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

  1. Use the spec-typed null: cb.nullLiteral(String.class) (or the wanted type) instead of cb.literal(null).
  2. For IS NULL comparisons just call cb.isNull(path)/cb.isNotNull(path) rather than comparing against a null literal.
  3. 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

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


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