{"record":{"id":"0a99b323717cac34","repo":"hibernate/hibernate-orm","slug":"illegal-parameter-index-index-in-pattern-pa","errorCode":null,"errorMessage":"Illegal parameter index '<index>' in pattern: '<pattern>'","messagePattern":"Illegal parameter index '<index>' in pattern: '<pattern>'","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java","lineNumber":138,"sourceCode":"\t\tthis.chunks = chunkList.toArray( EMPTY_STRING_ARRAY );\n\t\tint[] paramIndexes = new int[paramList.size()];\n\t\tfor ( i = 0; i < paramIndexes.length; ++i ) {\n\t\t\tparamIndexes[i] = paramList.get( i );\n\t\t}\n\t\tthis.paramIndexes = paramIndexes;\n\t\tthis.argumentRenderingModes = argumentRenderingModes;\n\t}\n\n\tprivate static int parameterIndex(String pattern, String index) {\n\t\tif ( index.isEmpty() ) {\n\t\t\tthrow new IllegalArgumentException( \"Missing parameter index in pattern: '\" + pattern + \"'\" );\n\t\t}\n\t\tfinal int paramNumber;\n\t\ttry {\n\t\t\tparamNumber = parseInt( index );\n\t\t}\n\t\tcatch (NumberFormatException nfe) {\n\t\t\tthrow new IllegalArgumentException( \"Illegal parameter index '\" + index\n\t\t\t\t\t\t\t\t\t\t\t\t+ \"' in pattern: '\" + pattern + \"'\", nfe );\n\t\t}\n\t\treturn paramNumber;\n\t}\n\n\tpublic boolean hasVarargs() {\n\t\treturn varargParam >= 0;\n\t}\n\n\tpublic int getParamCount() {\n\t\treturn maxParamIndex;\n\t}\n\n\t/**\n\t * The rendering code.\n\t *\n\t * @param sqlAppender Target for appending\n\t * @param args The arguments to inject into the template","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java#L120-L156","documentation":"The same PatternRenderer.parameterIndex parse step: after '?', the index text is parsed with Integer.parseInt, and a NumberFormatException is chained into IllegalArgumentException('Illegal parameter index ...') when that text is not a plain integer. Like the missing-index case, this fails when the renderer is built, i.e. during function registration at startup.","triggerScenarios":"A pattern whose placeholder index part is not a pure integer: \"date_trunc(?unit, ?1)\", \"trunc(?1, ?start)\", or an index glued to letters like '?1x'.","commonSituations":"Typos when hand-editing patterns; template substitution that mangles placeholder numbers; mixing PostgreSQL-style $1 placeholders with '?' placeholders in one pattern.","solutions":["Fix the placeholder to a plain integer index: ?2.","If text was intended right after a placeholder, move it outside the placeholder token: \"(?1, ?2)\" instead of \"(?1, ?2d)\".","Add a construction-time test for every registered pattern so bad indexes fail the build."],"exampleFix":"// before\n\"date_trunc(?unit, ?1)\"\n\n// after\n\"date_trunc(?2, ?1)\"","handlingStrategy":"validation","validationCode":"static void assertPatternIndexes(String pattern) {\n    for (int i = 0; i < pattern.length(); i++) {\n        if (pattern.charAt(i) != '?') continue;\n        int j = i + 1;\n        while (j < pattern.length() && Character.isDigit(pattern.charAt(j))) j++;\n        boolean empty = (j == i + 1);\n        boolean gluedLetter = j < pattern.length() && Character.isLetter(pattern.charAt(j));\n        if (empty || gluedLetter) {\n            throw new IllegalArgumentException(\"Bad parameter index at char \" + i + \" in pattern: \" + pattern);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new PatternRenderer(pattern);\n} catch (IllegalArgumentException e) {\n    throw new IllegalStateException(\"Bad SQL pattern for function '\" + name + \"': '\" + pattern + \"'\", e);\n}","preventionTips":["Placeholder indexes must be pure integers: ?1, ?2 - never ?start or ?1x.","Keep template substitution that builds patterns out of the placeholder tokens.","Test-render every registered pattern once in CI."],"tags":["hibernate","pattern-renderer","function-registration","sql-pattern","bootstrap"],"backgroundTag":"invalid-function-pattern","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}