{"record":{"id":"3f17653d503615f3","repo":"pentaho/pentaho-kettle","slug":"arrayindexoutofboundsexception-rownr","errorCode":null,"errorMessage":"ArrayIndexOutOfBoundsException( rownr )","messagePattern":"ArrayIndexOutOfBoundsException\\( rownr \\)","errorType":"exception","errorClass":"ArrayIndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"plugins/excel/core/src/main/java/org/pentaho/di/trans/steps/excelinput/staxpoi/StaxPoiSheet.java","lineNumber":200,"sourceCode":"          break;\n        }\n      }\n    }\n  }\n\n  boolean isMaxColsNumberDefined() {\n    return maxColsNumberDefined;\n  }\n\n  @Override\n  public KCell[] getRow( int rownr ) {\n    // xlsx raw row numbers are 1-based index, KSheet is 0-based\n\n    // Don't check the upper limit as not all rows may have been read!\n    // If it's found that the row does not exist, the exception will be thrown at the end of this method.\n    if ( rownr < 0 ) {\n      // KSheet requires out of bounds here\n      throw new ArrayIndexOutOfBoundsException( rownr );\n    }\n    if ( rownr + 1 < firstRow ) {\n      // before first non-empty row\n      return new KCell[0];\n    }\n    if ( rownr > 0 && currentRow == rownr + 1 ) {\n      if ( currentRowCells != null ) {\n        return currentRowCells;\n      }\n      // The case when the table contains the empty row(s) before the header\n      // but at the same time user wants to read starting from 0 row\n      return new KCell[0];\n    }\n    try {\n      if ( currentRow >= rownr + 1 ) {\n        // allow random access per api despite performance hit\n        resetSheetReader();\n      }","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/excel/core/src/main/java/org/pentaho/di/trans/steps/excelinput/staxpoi/StaxPoiSheet.java#L182-L218","documentation":"StaxPoiSheet.getRow() throws ArrayIndexOutOfBoundsException for row indexes below 0. KSheet's getRow contract is 0-based, while xlsx row numbers in the file are 1-based, so a negative index can never be valid. The method explicitly throws this exception to satisfy the KSheet out-of-bounds requirement.","triggerScenarios":"Calling sheet.getRow(-1) or any negative row number, e.g. loops that decrement below 0 or code that passes an uninitialized/off-by-one variable as rownr.","commonSituations":"Off-by-one errors when mixing 0-based KSheet indexes with 1-based xlsx row attributes ('r'); iterating getRows() times with wrong bounds; counter arithmetic bugs in ExcelInput step logic.","solutions":["Fix the caller to never pass a negative row index; KSheet rows are 0-based","Clamp the row index to >= 0 before calling getRow","If iterating, use for (int i = 0; i < sheet.getRows(); i++)","Catch ArrayIndexOutOfBoundsException if a negative probe is intentional"],"exampleFix":"// before\nKCell[] cells = sheet.getRow(rowIndex); // rowIndex could be -1\n// after\nKCell[] cells = rowIndex >= 0 ? sheet.getRow(rowIndex) : new KCell[0];","handlingStrategy":"validation","validationCode":"if (rownr < 0) { throw new IllegalArgumentException(\"row index must be >= 0, got \" + rownr); }\nKCell[] cells = sheet.getRow(rownr);","typeGuard":"boolean isValidRow(int rownr) { return rownr >= 0; }","tryCatchPattern":"try {\n  KCell[] cells = sheet.getRow(rownr);\n} catch (ArrayIndexOutOfBoundsException e) {\n  // negative index; fix caller bounds\n}","preventionTips":["Remember KSheet rows are 0-based while xlsx 'r' attributes are 1-based","Bound loops with i < sheet.getRows()","Clamp indexes from external input before calling getRow"],"tags":["arrayindexoutofbounds","excel","off-by-one"],"backgroundTag":"index-out-of-bounds","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}