Hibernate throws org.hibernate.QueryException with the message “Cannot mix named and positional parameters” when one stored procedure call registers some parameters by name and others by position. A named parameter is identified by a name such as p_from, whereas a positional parameter is identified by a number such as 2. Hibernate 4.3 to 5.2 print this exact text, while Hibernate 5.3 to 7.4 reject the same call with a reworded IllegalArgumentException and check HQL and native queries in their own way. In every version, the fix is to use one parameter style per call and per query.
We meet the error when we call a stored procedure with StoredProcedureQuery, often after passing the values where the parameter names belong.
The following example shows the error text in both version ranges, followed by a stored procedure call in the wrong and the right way.
java.lang.IllegalArgumentException: org.hibernate.QueryException: Cannot mix named and positional parameters
Caused by: org.hibernate.QueryException: Cannot mix named and positional parameters
java.lang.IllegalArgumentException: Cannot mix positional parameter with named parameter registrations
// Wrong: a name, then a position
StoredProcedureQuery wrong = em.createStoredProcedureQuery("count_departures")
.registerStoredProcedureParameter("p_from", String.class, ParameterMode.IN)
.registerStoredProcedureParameter(2, Integer.class, ParameterMode.IN); // IllegalArgumentException
// Right: names only
Object count = em.createStoredProcedureQuery("count_departures")
.registerStoredProcedureParameter("p_from", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("p_hour", Integer.class, ParameterMode.IN)
.setParameter("p_from", "Delhi")
.setParameter("p_hour", 7)
.getSingleResult(); // 2
Notice that the wrong call registers p_from by name and the second parameter by position 2, whereas the right call uses names only.
Next, we see why each Hibernate version reacts differently and how to fix the call and the query.
1. Named and Positional Parameters
A query parameter is a placeholder in the query text, and we set its value with setParameter(). Hibernate sends the value to the database separately from the SQL text. Jakarta Persistence defines two styles.
| Named parameter | Positional parameter | |
|---|---|---|
| In the query | :from | ?1 |
| Set with | setParameter(“from”, “Delhi”) | setParameter(1, “Delhi”) |
| In a stored procedure call | registerStoredProcedureParameter(“p_from”, …) | registerStoredProcedureParameter(1, …) |
| Readability | The name says what the value is | Only a number |
| Native SQL in the JPA spec | Not defined, Hibernate supports it | Portable |
Native SQL has a third form, the plain JDBC placeholder ? without a number. Before Hibernate runs a query, it scans the text for parameters and replaces each one with a JDBC ?.

2. Why Hibernate Cannot Mix the Parameters
Our example is a train timetable in an in-memory H2 database with Hibernate 7.4.11 and Java 25. Each TrainService row is one train, and the departure time is a LocalTime.
@Id
@GeneratedValue
private Long id;
private int trainNumber;
private String fromStation;
private String toStation;
private LocalTime departsAt;
| trainNumber | fromStation | toStation | departsAt |
|---|---|---|---|
| 101 | Delhi | Mumbai | 06:00 |
| 102 | Delhi | Mumbai | 16:30 |
| 201 | Delhi | Jaipur | 07:15 |
| 301 | Mumbai | Pune | 09:45 |
2.1. Names and Positions in One Stored Procedure Call
The procedure count_departures(p_from, p_hour) counts the trains that leave a station at or after an hour. H2 runs it as a Java method registered with CREATE ALIAS; on MySQL or PostgreSQL it would be a CREATE PROCEDURE. We call stored procedures through StoredProcedureQuery. The first registerStoredProcedureParameter() call fixes the style for the whole call.
A common way to mix the styles is to pass the values where the procedure’s parameter names belong. For example, a timetable screen sends the station and the hour that the user picked, and the developer hands both variables to registerStoredProcedureParameter().
String from = "Delhi";
Integer hour = 7;
StoredProcedureQuery query = em.createStoredProcedureQuery("count_departures")
.registerStoredProcedureParameter(from, String.class, ParameterMode.IN) // named parameter "Delhi"
.registerStoredProcedureParameter(hour, Integer.class, ParameterMode.IN); // positional parameter 7
// IllegalArgumentException: Cannot mix positional parameter with named parameter registrations
The code compiles because StoredProcedureQuery has one overload that takes a String name and one that takes an int position, so Java unboxes the Integer and picks the int overload.

2.2. Named and Ordinal Parameters in HQL and JPQL
In HQL and JPQL, a numbered parameter such as ?1 is called an ordinal parameter. The Jakarta Persistence specification says “Positional and named parameters must not be mixed in a single query”. However, with default settings, Hibernate 7.4 runs an HQL query that mixes them without an error.
List<TrainService> trains = em.createQuery("from TrainService t where t.fromStation = :from and t.toStation = ?1", TrainService.class)
.setParameter("from", "Delhi")
.setParameter(1, "Mumbai")
.getResultList(); // trains 101 and 102
// select ... from TrainService ts1_0 where ts1_0.fromStation=? and ts1_0.toStation=?
Hibernate checks the no-mixing rule only in strict JPA query compliance mode, which we turn on with the hibernate.jpa.compliance.query setting, here on HibernatePersistenceConfiguration.
new HibernatePersistenceConfiguration("train-timetable")
.property(JpaComplianceSettings.JPA_QUERY_COMPLIANCE, true)
...
With strict mode on, the same query fails in createQuery(), and the message depends on which style comes first.
java.lang.IllegalArgumentException: org.hibernate.query.sqm.StrictJpaComplianceViolation: Cannot mix ordinal and named parameters
java.lang.IllegalArgumentException: org.hibernate.query.sqm.StrictJpaComplianceViolation: Cannot mix positional and named parameters
2.3. Mixed Styles in Native SQL
For native queries, Hibernate 7.4 rejects only the plain JDBC ? next to another style, and createNativeQuery() throws a ParameterRecognitionException, which is a PersistenceException.
Query query = em.createNativeQuery("select * from TrainService where fromStation = :from and toStation = ?", TrainService.class);
// org.hibernate.engine.query.ParameterRecognitionException: Cannot mix parameter styles between JDBC-style, ordinal and named in the same query
The combination of :from and ?1 runs and returns trains 101 and 102, although Hibernate 5.3 to 5.6 rejected it too, with the message Mixed parameter strategies …. So the behavior has changed between versions in each kind of query.

3. How to Fix It
We pick one style for each stored procedure call and each query, and keep it. Named parameters are the better default, because the name documents the value.
3.1. One Style per Stored Procedure Call
We register the procedure’s own parameter names and pass the values only to setParameter(). Using only positions works as well, as long as we start at 1.
Object count = em.createStoredProcedureQuery("count_departures")
.registerStoredProcedureParameter("p_from", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("p_hour", Integer.class, ParameterMode.IN)
.setParameter("p_from", "Delhi")
.setParameter("p_hour", 7)
.getSingleResult(); // 2
// {call count_departures(?,?)}
Object count = em.createStoredProcedureQuery("count_departures")
.registerStoredProcedureParameter(1, String.class, ParameterMode.IN)
.registerStoredProcedureParameter(2, Integer.class, ParameterMode.IN)
.setParameter(1, "Delhi")
.setParameter(2, 7)
.getSingleResult(); // 2
// {call count_departures(?,?)}
3.2. One Style per Query
A named parameter can appear more than once, so a query never needs a second style.
// Before: :from and ?1
String hql = "from TrainService t where t.fromStation = :from and t.toStation = ?1";
// After: names only
List<TrainService> trains = em.createQuery("from TrainService t where t.fromStation = :from and t.toStation = :to", TrainService.class)
.setParameter("from", "Delhi")
.setParameter("to", "Mumbai")
.getResultList(); // trains 101 and 102
// One name used twice
List<TrainService> cityTrains = em.createQuery("from TrainService t where t.fromStation = :city or t.toStation = :city", TrainService.class)
.setParameter("city", "Mumbai")
.getResultList(); // trains 101, 102 and 301
A mixed query that runs today still has three problems.
- It breaks the Jakarta Persistence rule, so it fails as soon as someone turns on strict compliance mode.
- It depends on the Hibernate version, because the same native query failed on Hibernate 5.3 to 5.6.
- The Hibernate user guide says “It’s not a good idea to mix named and ordinal parameters in a single query”, so we cannot count on the lenient behavior staying.
When we run the tests with hibernate.jpa.compliance.query set to true, Hibernate finds every mixed HQL query early.
4. Query Parameter FAQs
4.1. Why Does HQL Reject a Question Mark Without a Number?
Because HQL and JPQL in Hibernate 7.4 accept only numbered ordinal parameters, a plain ? fails in createQuery(), alone or next to :from.
java.lang.IllegalArgumentException: org.hibernate.query.ParameterLabelException: Unlabeled ordinal parameter ('?' rather than ?1)
So we write ?1 or use a named parameter instead. In native SQL, a plain ? works when the query uses no other style, and setParameter(1, …) sets the first one.
4.2. Why Does setParameter() Say There Is No Such Parameter?
Because Hibernate checks every name we set against the names it found in the query. A typo fails in setParameter(), whereas a parameter we forget to set fails only when the query runs.
| Mistake | Exception and message |
|---|---|
| setParameter(“station”, “Delhi”) for :from | IllegalArgumentException: No parameter named ‘:station’ in query with named parameters [from] |
| No setParameter(“from”, …) before getResultList() | QueryParameterException: No argument for named parameter ‘:from’ |
The list in brackets shows the names Hibernate found, which also helps with the colon problem in section 4.4.
4.3. Do Positional Parameters Start at 0 or 1?
They start at 1, both in the query and in setParameter(), so using 0 in either place fails.
| Mistake | Message |
|---|---|
| setParameter(0, “Delhi”) for ?1 | No parameter labelled ‘?0’ in query with ordinal parameters [1] |
| ?0 in the HQL query | Ordinal parameter labels start from ‘?0’ (ordinal parameters must be labelled from ‘?1’) |
4.4. Why Does a PostgreSQL :: Cast Break a Native Query?
Because Hibernate reads the colons right after a parameter as part of the parameter name. PostgreSQL, and H2 too, write a type cast as value::type, so :from::varchar becomes one parameter named from::varchar.
Query query = em.createNativeQuery("select trainNumber from TrainService where fromStation = :from::varchar")
.setParameter("from", "Delhi");
// IllegalArgumentException: No parameter named ':from' in query with named parameters [from::varchar]
We use cast(:from as varchar), or escape each colon with a backslash (two backslashes in a Java string).
String castQuery = "... where fromStation = cast(:from as varchar)"; // sent: cast(? as varchar), result [101, 102, 201]
String escapedQuery = "... where fromStation = :from\\:\\:varchar"; // sent: ?::varchar, result [101, 102, 201]
A cast after a column, such as departsAt::varchar, and colons inside a string literal such as ’06:00:00′ need no change. A colon directly before a column name does: in H2’s json_object(‘from’:fromStation), Hibernate reads :fromStation as a parameter and fails with No argument for named parameter ‘:fromStation’. Writing ‘from’\\:fromStation in the Java string, or adding a space after the colon, fixes it.
5. Conclusion
Cannot mix named and positional parameters comes from Hibernate 4.3 to 5.2, when one stored procedure call registers parameters both by name and by position, often because we passed values where the names belong. Newer versions reject that call with a reworded message, while Hibernate 7.4 runs HQL and native queries that combine :name and ?1. We still keep one style per call and per query, preferably named parameters, and run the tests with strict JPA compliance turned on.
6. References
- Jakarta Persistence 3.2 specification: Input Parameters
- Jakarta Persistence 3.2 specification: Positional Parameters in native queries
- StoredProcedureQuery JavaDoc (Jakarta Persistence 3.2)
- Hibernate ORM 7.4 User Guide: Binding arguments to query parameters
- Hibernate ORM 7.4 User Guide: hibernate.jpa.compliance.query
- PostgreSQL Documentation: Type Casts
Happy Learning !!