hibernate/hibernate-orm · error · ParameterRecognitionException
Cannot mix parameter styles between JDBC-style, ordinal and…
Error message
Cannot mix parameter styles between JDBC-style, ordinal and named in the same query
What it means
ParameterRecognizerImpl enforces one parameter style per query: a bare JDBC '?' sets ParameterStyle.JDBC. When a bare '?' is recognized after a named (':name') or JPA-ordinal ('?n') parameter was already seen, parameterStyle is NAMED and this ParameterRecognitionException is thrown. Mixing styles would make bind positions ambiguous, so Hibernate rejects it up front.
Solutions
- Use one style consistently: convert the bare '?' into a named parameter (':y') or convert everything to JPA ordinals (?1, ?2).
- For literal '?' operators in PostgreSQL JSONB SQL, replace them with the equivalent functions (jsonb_exists, jsonb_exists_any, jsonb_exists_all) or set hibernate.query.native.ignore_jdbc_parameters=true so bare '?' is not treated as a parameter.
- Escape/inline literal question marks through dialect-safe function calls instead of raw operators.
Example fix
-- before select * from person where x = :val and y = ? -- after select * from person where x = :val and y = :y
Defensive patterns
Strategy: validation
Validate before calling
static void validateSingleParameterStyle(String sql) {
String scrubbed = sql.replaceAll("'([^']*)'", "?").replaceAll("\"([^\"]*)\"", "?"); // ignore literals
var m = java.util.regex.Pattern.compile("\\?(\\d+)\\b|:(\\w+)|\\?").matcher(scrubbed);
boolean jdbc = false, namedOrOrdinal = false;
while (m.find()) {
if (m.group(1) != null || m.group(2) != null) namedOrOrdinal = true;
else jdbc = true;
}
if (jdbc && namedOrOrdinal) throw new IllegalArgumentException("Query mixes bare '?' with ':name'/'?n' parameters");
} Try / catch
try { session.createNativeQuery(sql); } catch (org.hibernate.query.ParameterRecognitionException e) { /* normalize all parameters to one style and rebuild the query */ throw e; } Prevention
- Pick one parameter style per codebase module and enforce it in review/lint.
- For PostgreSQL JSONB '?'-operators in native SQL, set hibernate.query.native.ignore_jdbc_parameters=true or use jsonb_exists/jsonb_exists_any functions.
- Run validateSingleParameterStyle in tests over native SQL constants.
When it happens
Trigger: A query string combining ':name' or '?1' with a bare '?', e.g. "... where x = :val and y = ?". The bare '?' can also come from literal SQL such as PostgreSQL JSONB operators (? ?| ?&) which the parser cannot distinguish from placeholders. Thrown at query creation during ParameterRecognizer callbacks.
Common situations: PostgreSQL JSONB queries using the ? / ?| / ?& operators alongside real named parameters; copy-pasted SQL fragments in different styles; partial migration of a query from '?' to ':name'.
Related errors
- Could not resolve NativeQuery parameter type
- Argument to query parameter has an incompatible type
- Can't infer collection type based on element expression
- Cannot coerce value ' ' [ ] to Long
- Cannot coerce value ' ' [ ] to Short
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f14836060e08ffd4.
Report an issue: GitHub.
Appendix: source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterRecognizerImpl.java:100
public ArrayList<ParameterOccurrence> getParameterList() {
return parameterList;
}
public String getAdjustedSqlString() {
return sqlStringBuffer.toString();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Recognition code
@Override
public void ordinalParameter(int sourcePosition) {
if ( parameterStyle == null ) {
parameterStyle = ParameterStyle.JDBC;
}
else if ( parameterStyle != ParameterStyle.JDBC ) {
throw new ParameterRecognitionException( "Cannot mix parameter styles between JDBC-style, ordinal and named in the same query" );
}
int implicitPosition = ordinalParameterImplicitPosition++;
QueryParameterImplementor<?> parameter = null;
if ( positionalQueryParameters == null ) {
positionalQueryParameters = new HashMap<>();
}
else {
parameter = positionalQueryParameters.get( implicitPosition );
}
if ( parameter == null ) {
parameter = QueryParameterPositionalImpl.fromNativeQuery( implicitPosition );
positionalQueryParameters.put( implicitPosition, parameter );
}
View on GitHub (pinned to fad1729dce)