hibernate/hibernate-orm · error · ParameterLabelException
Ordinal parameter labels start from '?{position}' (ordinal p
Error message
Ordinal parameter labels start from '?{position}' (ordinal parameters must be labelled from '?1') What it means
After parsing a query, ParameterRecognizerImpl.complete() validates that ordinal parameter labels form the sequence 1, 2, 3, ... with no gaps, as JPA requires. If the very first declared label is not '?1' it throws ParameterLabelException saying the labels start from '?{position}' and must be labelled from '?1'.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterRecognizerImpl.java:57
private final StringBuilder sqlStringBuffer = new StringBuilder();
public ParameterRecognizerImpl() {
ordinalParameterImplicitPosition = 1;
}
@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() {View on GitHub (pinned to fad1729dce)
Solutions
- Relabel the parameters starting at ?1 and incrementing by 1 (bind values by label, so renaming is safe with setParameter(1, ...)).
- Or switch the whole query to named parameters (:a, :b) which have no ordering requirement.
- If some parameters are optional, keep the ?n labels contiguous in the final SQL string you actually execute (build variants that still start at ?1).
Example fix
-- before select * from person where a = ?2 and b = ?3 -- after select * from person where a = ?1 and b = ?2
Defensive patterns
Strategy: validation
Validate before calling
static void validateOrdinalLabelsStartAtOne(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)));
if (!labels.isEmpty() && labels.first() != 1)
throw new IllegalArgumentException("Ordinal labels start at ?" + labels.first() + " — must start at ?1");
} Try / catch
try { em.createQuery(ql).getResultList(); } catch (org.hibernate.query.ParameterLabelException e) { /* renumber labels from ?1 and retry once */ throw e; } Prevention
- Never hard-code ?n values in dynamically assembled SQL; renumber as you build.
- Add the label-sequence validation above to query-builder utilities and unit tests.
When it happens
Trigger: A query using explicit JPA ordinal labels whose smallest label is greater than 1, e.g. "select p from P p where p.a = ?2 and p.b = ?3" with no ?1. Fires at query creation when complete() runs, before parameter binding.
Common situations: Renumbering query fragments during refactoring and dropping ?1; concatenating WHERE clauses that start labels at arbitrary offsets; tooling that generates labels from non-1-based positions; code migrated from drivers that allowed 0-based or arbitrary labels.
Related errors
- Ordinal parameter label was not an integer
- Gap between '?{previous}' and '?{position}' in ordinal param
- Incoming parameter position [{position}] is less than base [
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/17b855e90a949938.
Report an issue: GitHub.