hibernate/hibernate-orm · error · ParameterLabelException

Ordinal parameter labels start from '?%s' (ordinal parameter

Error message

Ordinal parameter labels start from '?%s' (ordinal parameters must be labelled from '?1')

What it means

When Hibernate parses HQL/JPQL it validates that ordinal parameter labels are consecutive integers starting at 1. ParameterMetadataImpl.verifyOrdinalParamLabels sorts the labels and throws ParameterLabelException at query creation when the smallest label is not 1. This matches the JPA spec and is stricter than Hibernate 5, which tolerated arbitrary positional labels.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java:135

				queryParameters.put( queryParameter, emptyList() );
				tempQueryParametersByName.put( queryParameter.getName(), queryParameter );
			}
		}
		queryParametersByPosition = tempQueryParametersByPosition;
		queryParametersByName = tempQueryParametersByName;
		queryParameterBindingsTemplate = QueryParameterBindingsImpl.from( this, null );
	}

	private static void verifyOrdinalParamLabels(Set<Integer> labels) {
		if ( !isEmpty( labels ) ) {
			final List<Integer> sortedLabels = new ArrayList<>( labels );
			sortedLabels.sort( ComparableComparator.instance() );

			int lastPosition = -1;
			for ( Integer sortedPosition : sortedLabels ) {
				if ( lastPosition == -1 ) {
					if ( sortedPosition != 1 ) {
						throw new ParameterLabelException(
								String.format(
										Locale.ROOT,
										"Ordinal parameter labels start from '?%s' (ordinal parameters must be labelled from '?1')",
										sortedPosition
								)
						);
					}
				}
				else {
					if ( sortedPosition != lastPosition + 1 ) {
						throw new ParameterLabelException(
								String.format(
										Locale.ROOT,
										"Gap between '?%s' and '?%s' in ordinal parameter labels [%s] (ordinal parameters must be labelled sequentially)",
										lastPosition,
										sortedPosition,
										join( ",", sortedLabels.iterator() )
								)

View on GitHub (pinned to fad1729dce)

Solutions

  1. Renumber the ordinal labels in the query string so they start at ?1.
  2. Prefer named parameters (:name) so labels can never go stale.
  3. If many migrated queries are affected, add a startup or test-time check that parses each HQL string and validates the labels before first use.

Example fix

// before
List<Person> people = session
    .createQuery("from Person p where p.age > ?2", Person.class)
    .list(); // ParameterLabelException: labels must start from '?1'

// after
List<Person> people = session
    .createQuery("from Person p where p.age > ?1", Person.class)
    .list();
Defensive patterns

Strategy: validation

Validate before calling

static void checkOrdinalLabels(String hql) {
    java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\?(\\d+)").matcher(hql);
    java.util.TreeSet<Integer> labels = new java.util.TreeSet<>();
    while (m.find()) labels.add(Integer.parseInt(m.group(1)));
    int expected = 1;
    for (int label : labels) {
        if (label != expected) throw new IllegalArgumentException(
            "Ordinal labels must start at ?1 and be sequential; offending label ?" + label);
        expected++;
    }
}

Try / catch

try {
    em.createQuery(hql);
} catch (IllegalArgumentException e) { // ParameterLabelException extends it
    // surface 'labels start from ?1' to the caller / fail the test
}

Prevention

When it happens

Trigger: Creating a query whose first (lowest) ordinal label is greater than 1, e.g. createQuery("... where p.age > ?2") or one starting at ?3. The exception is thrown while building ParameterMetadata, before any parameter is bound or the query executes.

Common situations: Upgrading Hibernate 5 to 6/7 where legacy queries kept arbitrary ?N numbers; deleting the first parameter from a query string and leaving later labels unshifted; copying numbered placeholders from SQL logs back into HQL.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/15bfb6329eb35996. Report an issue: GitHub.