hibernate/hibernate-orm · error · UnsupportedOperationException

Can't render expression as literal:

Error message

Can't render expression as literal: 

What it means

The fall-through of renderExpressionAsLiteral: the expression is neither a Literal, a JdbcParameter, nor a SqmParameterInterpretation — e.g., a function call, CASE, arithmetic, or star expression — while a dialect emulation needs it as an inline SQL literal, so translation aborts with UnsupportedOperationException("Can't render expression as literal: " + expression). It is the rendering-side sibling of 'Can't interpret expression'.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java:700

			expression.accept( this );
			return;
		}
		else if ( expression instanceof JdbcParameter parameter ) {
			if ( jdbcParameterBindings == null ) {
				throw new IllegalArgumentException( "Can't interpret expression because no parameter bindings are available" );
			}
			renderAsLiteral( parameter, getParameterBindValue( parameter ) );
			return;
		}
		else if ( expression instanceof SqmParameterInterpretation parameterInterpretation ) {
			if ( jdbcParameterBindings == null ) {
				throw new IllegalArgumentException( "Can't interpret expression because no parameter bindings are available" );
			}
			final JdbcParameter parameter = (JdbcParameter) parameterInterpretation.getResolvedExpression();
			renderAsLiteral( parameter, getParameterBindValue( parameter ) );
			return;
		}
		throw new UnsupportedOperationException( "Can't render expression as literal: " + expression );
	}

	protected Object getParameterBindValue(JdbcParameter parameter) {
		final JdbcParameterBinding binding;
		if ( parameter == getOffsetParameter() ) {
			binding = new JdbcParameterBindingImpl( getIntegerType(), getLimit().getFirstRow() );
		}
		else if ( parameter == getLimitParameter() ) {
			binding = new JdbcParameterBindingImpl( getIntegerType(), getLimit().getMaxRows() );
		}
		else {
			binding = jdbcParameterBindings.getBinding( parameter );
		}
		addAppliedParameterBinding( parameter, binding );
		return binding.getBindValue();
	}

	protected Expression getLeftHandExpression(Predicate predicate) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Replace the expression with a literal value or a bound parameter (parameters are renderable when bindings exist; functions/CASE are not).
  2. Move the expression outside the emulated fragment or compute it in application code.
  3. Use a native SQL query for this statement.
  4. Upgrade hibernate-core — literal-rendering coverage differs per version and dialect.

Example fix

// before — emulation must render the function as a literal and cannot
List<Pricing> ps = session.createQuery(
    "select p from Pricing p where lower(p.currency) = :ccy", Pricing.class).list();

// after — bind a plain value computed in Java so only literals/parameters remain
List<Pricing> ps = session.createQuery(
    "select p from Pricing p where p.currency = :ccy", Pricing.class)
    .setParameter("ccy", "EUR").list();
Defensive patterns

Strategy: try-catch

Try / catch

try {
    query.list();
} catch (UnsupportedOperationException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Can't render expression as literal")) {
        // expression cannot be rendered inline: replace with literal/parameter or use native SQL
        rows = runNativeFallback();
    } else { throw e; }
}

Prevention

When it happens

Trigger: An emulation that must write the value of an expression directly into SQL (renderExpressionAsLiteral) receives a non-literal, non-parameter expression — typically a function/CASE/arithmetic node placed where the dialect can only emit a literal.

Common situations: Expressions inside fragments a dialect emulates literally (limit clauses, CTE or set-operation emulations); queries portable on one DB but not another; Hibernate upgrades activating new literal-rendering paths; criteria dynamically building CASE expressions.

Related errors


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