{"record":{"id":"17b855e90a949938","repo":"hibernate/hibernate-orm","slug":"ordinal-parameter-labels-start-from-position","errorCode":null,"errorMessage":"Ordinal parameter labels start from '?{position}' (ordinal parameters must be labelled from '?1')","messagePattern":"Ordinal parameter labels start from '\\?(.+?)' \\(ordinal parameters must be labelled from '\\?1'\\)","errorType":"exception","errorClass":"ParameterLabelException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterRecognizerImpl.java","lineNumber":57,"sourceCode":"\tprivate final StringBuilder sqlStringBuffer = new StringBuilder();\n\n\tpublic ParameterRecognizerImpl() {\n\t\tordinalParameterImplicitPosition = 1;\n\t}\n\n\t@Override\n\tpublic void complete() {\n\t\t// validate the positions.  JPA says that these should start with 1 and\n\t\t// increment contiguously (no gaps)\n\t\tif ( positionalQueryParameters != null ) {\n\t\t\tfinal int[] positionsArray = positionalQueryParameters.keySet().stream().mapToInt( Integer::intValue ).toArray();\n\t\t\tArrays.sort( positionsArray );\n\t\t\tint previous = 0;\n\t\t\tboolean first = true;\n\t\t\tfor ( Integer position : positionsArray ) {\n\t\t\t\tif ( position != previous + 1 ) {\n\t\t\t\t\tif ( first ) {\n\t\t\t\t\t\tthrow new ParameterLabelException(\n\t\t\t\t\t\t\t\t\"Ordinal parameter labels start from '?\" + position + \"'\"\n\t\t\t\t\t\t\t\t\t\t+ \" (ordinal parameters must be labelled from '?1')\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthrow new ParameterLabelException(\n\t\t\t\t\t\t\t\t\"Gap between '?\" + previous + \"' and '?\" + position + \"' in ordinal parameter labels\"\n\t\t\t\t\t\t\t\t\t\t+ \" (ordinal parameters must be labelled sequentially)\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfirst = false;\n\t\t\t\tprevious = position;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic Map<String, QueryParameterImplementor<?>> getNamedQueryParameters() {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterRecognizerImpl.java#L39-L75","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"-- before\nselect * from person where a = ?2 and b = ?3\n\n-- after\nselect * from person where a = ?1 and b = ?2","handlingStrategy":"validation","validationCode":"static void validateOrdinalLabelsStartAtOne(String sql) {\n    var labels = new java.util.TreeSet<Integer>();\n    var m = java.util.regex.Pattern.compile(\"\\\\?(\\\\d+)\").matcher(sql);\n    while (m.find()) labels.add(Integer.parseInt(m.group(1)));\n    if (!labels.isEmpty() && labels.first() != 1)\n        throw new IllegalArgumentException(\"Ordinal labels start at ?\" + labels.first() + \" — must start at ?1\");\n}","typeGuard":null,"tryCatchPattern":"try { em.createQuery(ql).getResultList(); } catch (org.hibernate.query.ParameterLabelException e) { /* renumber labels from ?1 and retry once */ throw e; }","preventionTips":["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."],"tags":["hibernate","ordinal-parameter","positional-parameter","parameter-label-exception","jpa"],"backgroundTag":"jpa-ordinal-parameter-label-invalid","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}