hibernate/hibernate-orm · error · IllegalArgumentException
Can't render parameter as literal, no literal formatter…
Error message
Can't render parameter as literal, no literal formatter found
What it means
In certain SQL positions Hibernate must render a JDBC parameter inline as a literal (e.g. limit/offset values on dialects that cannot bind parameters there, or inlined static parameters). renderAsLiteral asks the parameter's JdbcMapping for a JdbcLiteralFormatter; if the mapping provides none (common for exotic/basic-java-type mappings), rendering is impossible and this IllegalArgumentException is thrown.
Solutions
- Use a standard Java/JDBC type for the parameter (Integer, String, LocalDate...) that has a built-in formatter
- For custom types, register a BasicType/JavaType that supplies a JdbcLiteralFormatter
- Avoid the construct that forces literal rendering (e.g. use setMaxResults so the dialect takes the native parameter path)
- Upgrade Hibernate - formatter coverage for more JDBC types improves by version
Example fix
// before
custom BasicType without literal formatter used where dialect inlines parameters
// after
// register the type with a formatter
BasicType<MyType> t = new MyTypeRenderer(new MyTypeJavaType() {
@Override public JdbcLiteralFormatter<MyType> getJdbcLiteralFormatter() { return (appender, value, dialect, wrapper) -> appender.appendSql(value.render()); }
}); Defensive patterns
Strategy: fallback
Validate before calling
// Before executing with inlined parameters, confirm the mapping can render literals
JdbcMapping m = (JdbcMapping) param.getExpressionType().getSingleJdbcMapping();
if (m.getJdbcLiteralFormatter() == null) {
// switch the parameter to a standard type or avoid the literal-rendering construct
} Try / catch
try {
query.list();
} catch (IllegalArgumentException e) {
if ("Can't render parameter as literal, no literal formatter found".equals(e.getMessage())) {
// rebind the parameter with a standard Java type and retry
} else throw e;
} Prevention
- Bind parameters as standard Java types (Integer, String, LocalDate...)
- For custom types, always provide a JdbcLiteralFormatter in the JavaType/BasicType
- Prefer setMaxResults/setFirstResult over constructs that force literal rendering
When it happens
Trigger: A query whose parameter must be rendered literally (dialect-specific limit emulation, in-clause parameter inlining, or explicit literal rendering mode) where the bound parameter's type has getJdbcLiteralFormatter() == null - e.g. custom BasicType/JavaType without a literal formatter, or certain binary/java-object mappings.
Common situations: Custom UserTypes/BasicTypes that implement the binder but not the literal formatter; pagination on dialects that inline the fetch value; switching a parameter's Java type to one lacking formatter support; Hibernate 6 migration where literal rendering paths expanded.
Related errors
- Annotation ' ' is not assignable to
- Can't emulate equality preserving row constructor through…
- Can't emulate offset fetch clause in subquery
- Can't emulate order preserving row constructor through…
- Class '" + typeName + "' does not implement '" +…
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/0e558d1859f6377e.
Report an issue: GitHub.
Appendix: source
Thrown at hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java:7656
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) {
renderCasted( literal );
}
else {
appendSql( SqlAppender.NULL_KEYWORD );
}
}
protected void renderAsLiteral(JdbcParameter jdbcParameter, Object literalValue) {
if ( literalValue == null ) {
renderNull( new QueryLiteral<>( null, (BasicValuedMapping) jdbcParameter.getExpressionType() ) );
}
else {
assert jdbcParameter.getExpressionType().getJdbcTypeCount() == 1;
final JdbcMapping jdbcMapping = jdbcParameter.getExpressionType().getSingleJdbcMapping();
//noinspection unchecked
final JdbcLiteralFormatter<Object> literalFormatter = jdbcMapping.getJdbcLiteralFormatter();
if ( literalFormatter == null ) {
throw new IllegalArgumentException( "Can't render parameter as literal, no literal formatter found" );
}
else {
literalFormatter.appendJdbcLiteral( this, literalValue, dialect, getWrapperOptions() );
}
}
}
@Override
public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) {
if ( unaryOperationExpression.getOperator() == UnaryArithmeticOperator.UNARY_PLUS ) {
appendSql( UnaryArithmeticOperator.UNARY_PLUS.getOperatorChar() );
}
else {
appendSql( UnaryArithmeticOperator.UNARY_MINUS.getOperatorChar() );
}
unaryOperationExpression.getOperand().accept( this );
}View on GitHub (pinned to fad1729dce)