hibernate/hibernate-orm · error · IllegalArgumentException

Can't render value because java type is null

Error message

Can't render value because java type is null

What it means

When an SQM tree is rendered back to HQL (query-plan cache keys, diagnostics, criteria-to-HQL display), SqmLiteral.appendHqlString stringifies a non-null value through its JavaType. If the literal was constructed without a type (null JavaType), rendering is impossible and it throws IllegalArgumentException('Can't render value because java type is null').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmLiteral.java:94

	}

	@Override
	public String asLoggableText() {
		return "Literal( " + getLiteralValue() + ")";
	}

	@Override
	public void appendHqlString(StringBuilder hql, SqmRenderContext context) {
		appendHqlString( hql, getJavaTypeDescriptor(), getLiteralValue() );
	}

	public static <T> void appendHqlString(StringBuilder sb, @Nullable JavaType<T> javaType, @Nullable T value) {
		if ( value == null ) {
			sb.append( "null" );
		}
		else {
			if ( javaType == null ) {
				throw new IllegalArgumentException( "Can't render value because java type is null" );
			}
			if ( value instanceof Number || value instanceof Boolean ) {
				// We know these are safe to render
				sb.append( value );
			}
			else if ( value instanceof Enum<?> enumValue ) {
				sb.append( enumValue.getDeclaringClass().getTypeName() ).append( "." ).append( enumValue.name() );
			}
			else {
				// Even if this is not 100% correct, our goal with this implementation is to provide
				// a cache key or insight into the query structure, not necessarily produce an executable query
				appendSingleQuoteEscapedString( sb, javaType.toString( value ) );
			}
		}
	}

	@Override
	public boolean equals(@Nullable Object object) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Create literals through nodeBuilder().literal(value), which resolves the JavaType automatically.
  2. When constructing SqmLiteral manually, always pass a non-null type, e.g. nodeBuilder().getTypeConfiguration().getBasicTypeForJavaType(value.getClass()).
  3. In custom nodes, initialize the type eagerly (setExpressibleType) before the query is rendered.

Example fix

// before
new SqmLiteral<>( value, null, nodeBuilder ); // appendHqlString later -> IllegalArgumentException

// after
nodeBuilder.literal( value );
// or
new SqmLiteral<>( value, nodeBuilder.getTypeConfiguration().getBasicTypeForJavaType( value.getClass() ), nodeBuilder );
Defensive patterns

Strategy: validation

Validate before calling

JavaType<?> jt = literal.getJavaTypeDescriptor();
if ( literal.getLiteralValue() != null && jt == null ) {
    throw new IllegalStateException( "literal has no JavaType - rebuild it via nodeBuilder().literal(value)" );
}

Prevention

When it happens

Trigger: Constructing SqmLiteral (or a subclass) directly with a null SqmTypedNode/inherent type but a non-null value - new SqmLiteral<>(value, null, nodeBuilder) - and then triggering HQL rendering via createQuery, tree copy, or logging; also custom SqmExpression implementations whose getNodeType()/getJavaTypeDescriptor() returns null.

Common situations: Custom SQM node subclasses with lazy or missing types; literals created while a query is half-built; tree copies that drop type information; Hibernate upgrades changing when literal types get attached.

Related errors


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