{"record":{"id":"5cb7929473d6bcf6","repo":"hibernate/hibernate-orm","slug":"given-index-was-outside-the-range-of-result-t","errorCode":null,"errorMessage":"Given index [{}] was outside the range of result tuple size [{}] ","messagePattern":"Given index \\[(.+?)\\] was outside the range of result tuple size \\[(.+?)\\] ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/results/internal/TupleImpl.java","lineNumber":92,"sourceCode":"\tpublic <X> X get(int i, Class<X> type) {\n\t\tfinal Object result = get( i );\n\t\tif ( result != null && !isInstance( type, result ) ) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"Requested tuple value [index=%s, realType=%s] cannot be assigned to requested type [%s]\",\n\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\tresult.getClass().getName(),\n\t\t\t\t\t\t\ttype.getName()\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\treturn cast( type, result );\n\t}\n\n\t@Override\n\tpublic Object get(int i) {\n\t\tif ( i >= row.length ) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Given index [\" + i + \"] was outside the range of result tuple size [\" + row.length + \"] \"\n\t\t\t);\n\t\t}\n\t\treturn row[i];\n\t}\n\n\t@Override\n\tpublic Object[] toArray() {\n\t\treturn row;\n\t}\n\n\t@Override\n\tpublic List<TupleElement<?>> getElements() {\n\t\treturn tupleMetadata.getList();\n\t}\n\n\t@Override\n\tpublic String toString() {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/results/internal/TupleImpl.java#L74-L110","documentation":"Thrown by TupleImpl.get(int i) when the requested index is at or beyond the tuple size (row length). The message reports both the index and the size. Note the guard only checks the upper bound: a negative index is not checked here and would instead surface as an ArrayIndexOutOfBoundsException from the underlying array access.","triggerScenarios":"`tuple.get(3)` on a 3-column select (valid indices 0-2); looping `for (int i=1; i<=size; i++) tuple.get(i)` - off-by-one treating positions as 1-based (JPA tuple indices are 0-based); select list shortened during refactoring while reader code kept old indices.","commonSituations":"Confusing JDBC 1-based column positions with Tuple 0-based indices; hardcoded indices drifting after query changes; reading dynamic projections where the column count varies.","solutions":["Use 0-based indices strictly below size: valid range is `0 .. tuple.toArray().length - 1`","Prefer alias-based access (`tuple.get(\"name\")`) to eliminate index drift entirely","Derive the loop bound from the tuple itself: `Object[] arr = tuple.toArray(); for (int i=0; i<arr.length; i++)`"],"exampleFix":"// before\nfor (int i = 1; i <= tuple.toArray().length; i++) { Object v = tuple.get(i); }\n// after\nObject[] arr = tuple.toArray();\nfor (int i = 0; i < arr.length; i++) { Object v = arr[i]; }","handlingStrategy":"validation","validationCode":"// Bounds check before indexed access (indices are 0-based)\nint size = tuple.toArray().length;\nif (i < 0 || i >= size) throw new IndexOutOfBoundsException(\"tuple index \" + i + \" of size \" + size);","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) { if (e.getMessage().contains(\"outside the range of result tuple size\")) { /* clamp or skip */ } throw e; }","preventionTips":["Remember: JPA Tuple indices are 0-based, unlike JDBC column positions (1-based)","Derive loop bounds from tuple.toArray().length, never from a hardcoded column count","Map indices once next to the query definition so reordering forces a visible update"],"tags":["tuple","jpa","index-out-of-bounds","off-by-one"],"backgroundTag":"tuple-element-access","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}