hibernate/hibernate-orm · error · ParameterLabelException
Gap between '?{previous}' and '?{position}' in ordinal param
Error message
Gap between '?{previous}' and '?{position}' in ordinal parameter labels (ordinal parameters must be labelled sequentially) What it means
The complement of the first-label check: ParameterRecognizerImpl.complete() walks the sorted ordinal labels and requires each to equal previous + 1. When a later label skips a number (e.g. ?1 then ?3) it throws ParameterLabelException reporting the gap — JPA demands strictly sequential labels.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterRecognizerImpl.java:63
@Override
public void complete() {
// validate the positions. JPA says that these should start with 1 and
// increment contiguously (no gaps)
if ( positionalQueryParameters != null ) {
final int[] positionsArray = positionalQueryParameters.keySet().stream().mapToInt( Integer::intValue ).toArray();
Arrays.sort( positionsArray );
int previous = 0;
boolean first = true;
for ( Integer position : positionsArray ) {
if ( position != previous + 1 ) {
if ( first ) {
throw new ParameterLabelException(
"Ordinal parameter labels start from '?" + position + "'"
+ " (ordinal parameters must be labelled from '?1')"
);
}
else {
throw new ParameterLabelException(
"Gap between '?" + previous + "' and '?" + position + "' in ordinal parameter labels"
+ " (ordinal parameters must be labelled sequentially)"
);
}
}
first = false;
previous = position;
}
}
}
public Map<String, QueryParameterImplementor<?>> getNamedQueryParameters() {
return namedQueryParameters;
}
public Map<Integer, QueryParameterImplementor<?>> getPositionalQueryParameters() {
return positionalQueryParameters;
}View on GitHub (pinned to fad1729dce)
Solutions
- Renumber all labels contiguously 1..N in the final query string; renumber programmatically when assembling dynamic SQL.
- Use named parameters when fragments are combined dynamically — they are order- and gap-free.
- Wrap dynamic assembly with a helper that rewrites '?k' tokens to sequential values as fragments are appended.
Example fix
-- before select * from person where a = ?1 and b = ?3 -- after select * from person where a = ?1 and b = ?2
Defensive patterns
Strategy: validation
Validate before calling
static void validateOrdinalLabelsContiguous(String sql) {
var labels = new java.util.TreeSet<Integer>();
var m = java.util.regex.Pattern.compile("\\?(\\d+)").matcher(sql);
while (m.find()) labels.add(Integer.parseInt(m.group(1)));
int expected = 1;
for (int l : labels) {
if (l != expected) throw new IllegalArgumentException("Gap: expected ?" + expected + " but found ?" + l);
expected++;
}
} Try / catch
try { em.createQuery(ql).getResultList(); } catch (org.hibernate.query.ParameterLabelException e) { /* fix the reported gap between ?i and ?j */ throw e; } Prevention
- When deleting a parameter, renumber the remaining labels immediately.
- Use named parameters for queries assembled from optional fragments.
When it happens
Trigger: A query containing labels like ?1 and ?3 with no ?2 anywhere in the string, e.g. "... where a = ?1 or b = ?3". The gap can also appear after string concatenation of dynamic filter fragments that each hard-code their own labels.
Common situations: Dynamically appended conditions where each fragment uses fixed labels; deleting a parameter from a query but not renumbering the rest; merging two queries that each used ?1, ?2 into one string without renumbering.
Related errors
- Ordinal parameter label was not an integer
- Ordinal parameter labels start from '?{position}' (ordinal p
- Incoming parameter position [{position}] is less than base [
- Insert conflict 'do update' clause with constraint name is n
- field type not supported on Derby: " + unit
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/589ef26e25f51258.
Report an issue: GitHub.