{"record":{"id":"d7cddd5ae05a22a9","repo":"hibernate/hibernate-orm","slug":"gap-between-s-and-s-in-ordinal-parameter-l","errorCode":null,"errorMessage":"Gap between '?%s' and '?%s' in ordinal parameter labels [%s] (ordinal parameters must be labelled sequentially)","messagePattern":"Gap between '\\?(.+?)' and '\\?(.+?)' in ordinal parameter labels \\[(.+?)\\] \\(ordinal parameters must be labelled sequentially\\)","errorType":"exception","errorClass":"ParameterLabelException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java","lineNumber":146,"sourceCode":"\t\t\tfinal List<Integer> sortedLabels = new ArrayList<>( labels );\n\t\t\tsortedLabels.sort( ComparableComparator.instance() );\n\n\t\t\tint lastPosition = -1;\n\t\t\tfor ( Integer sortedPosition : sortedLabels ) {\n\t\t\t\tif ( lastPosition == -1 ) {\n\t\t\t\t\tif ( sortedPosition != 1 ) {\n\t\t\t\t\t\tthrow new ParameterLabelException(\n\t\t\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\t\t\t\"Ordinal parameter labels start from '?%s' (ordinal parameters must be labelled from '?1')\",\n\t\t\t\t\t\t\t\t\t\tsortedPosition\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif ( sortedPosition != lastPosition + 1 ) {\n\t\t\t\t\t\tthrow new ParameterLabelException(\n\t\t\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\t\t\t\"Gap between '?%s' and '?%s' in ordinal parameter labels [%s] (ordinal parameters must be labelled sequentially)\",\n\t\t\t\t\t\t\t\t\t\tlastPosition,\n\t\t\t\t\t\t\t\t\t\tsortedPosition,\n\t\t\t\t\t\t\t\t\t\tjoin( \",\", sortedLabels.iterator() )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastPosition = sortedPosition;\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic Collection<QueryParameter<?>> getParameters() {\n\t\treturn unmodifiableSet( queryParameters.keySet() );","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java#L128-L164","documentation":"After confirming ordinal labels start at 1, verifyOrdinalParamLabels walks the sorted labels and requires each to be exactly lastPosition + 1. A skipped number (for example ?1 followed by ?3) throws ParameterLabelException and the message prints the full label set so the gap is easy to spot. Like the start-from-1 rule, it fires at query creation time.","triggerScenarios":"A query string such as \"... where a = ?1 and b = ?3\" - the ?2 predicate was removed but later labels were never shifted down. Any gap between consecutive ordinal labels in one HQL/JPQL query triggers it.","commonSituations":"Removing a WHERE fragment from a query but leaving the remaining ?N numbers unchanged; assembling query strings from fragments where each fragment carries its own labels; Hibernate 5 to 6/7 migration since 5 did not enforce sequential labels.","solutions":["Renumber the remaining ordinal labels sequentially (1, 2, 3, ...) after deleting a parameter.","Switch the query to named parameters to make renumbering a non-issue.","Keep query strings in one place (constant or resource) instead of concatenating fragments with baked-in labels."],"exampleFix":"// before\nString hql = \"from Person p where p.name = ?1 and p.age > ?3\"; // gap: no ?2\n\n// after\nString hql = \"from Person p where p.name = ?1 and p.age > ?2\";","handlingStrategy":"validation","validationCode":"static void checkOrdinalLabels(String hql) {\n    java.util.regex.Matcher m = java.util.regex.Pattern.compile(\"\\\\?(\\\\d+)\").matcher(hql);\n    java.util.TreeSet<Integer> labels = new java.util.TreeSet<>();\n    while (m.find()) labels.add(Integer.parseInt(m.group(1)));\n    int expected = 1;\n    for (int label : labels) {\n        if (label != expected) throw new IllegalArgumentException(\n            \"Gap in ordinal labels: expected ?\" + expected + \" but found ?\" + label);\n        expected++;\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    em.createQuery(hql);\n} catch (IllegalArgumentException e) {\n    // message lists the full label set; renumber before retrying\n}","preventionTips":["Never concatenate query fragments that each carry their own ?N labels.","Keep each query string in one constant or resource file.","Prefer named parameters so labels cannot drift after edits."],"tags":["hibernate","hql","jpql","positional-parameters","parameter-labels","migration"],"backgroundTag":"positional-parameter-numbering","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}