pentaho/pentaho-kettle · error · ArrayIndexOutOfBoundsException

ArrayIndexOutOfBoundsException( rownr )

Error message

ArrayIndexOutOfBoundsException( rownr )

What it means

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.

Solutions

  1. Fix the caller to never pass a negative row index; KSheet rows are 0-based
  2. Clamp the row index to >= 0 before calling getRow
  3. If iterating, use for (int i = 0; i < sheet.getRows(); i++)
  4. Catch ArrayIndexOutOfBoundsException if a negative probe is intentional

Example fix

// before
KCell[] cells = sheet.getRow(rowIndex); // rowIndex could be -1
// after
KCell[] cells = rowIndex >= 0 ? sheet.getRow(rowIndex) : new KCell[0];
Defensive patterns

Strategy: validation

Validate before calling

if (rownr < 0) { throw new IllegalArgumentException("row index must be >= 0, got " + rownr); }
KCell[] cells = sheet.getRow(rownr);

Type guard

boolean isValidRow(int rownr) { return rownr >= 0; }

Try / catch

try {
  KCell[] cells = sheet.getRow(rownr);
} catch (ArrayIndexOutOfBoundsException e) {
  // negative index; fix caller bounds
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/3f17653d503615f3. Report an issue: GitHub.

Appendix: source

Thrown at plugins/excel/core/src/main/java/org/pentaho/di/trans/steps/excelinput/staxpoi/StaxPoiSheet.java:200

          break;
        }
      }
    }
  }

  boolean isMaxColsNumberDefined() {
    return maxColsNumberDefined;
  }

  @Override
  public KCell[] getRow( int rownr ) {
    // xlsx raw row numbers are 1-based index, KSheet is 0-based

    // Don't check the upper limit as not all rows may have been read!
    // If it's found that the row does not exist, the exception will be thrown at the end of this method.
    if ( rownr < 0 ) {
      // KSheet requires out of bounds here
      throw new ArrayIndexOutOfBoundsException( rownr );
    }
    if ( rownr + 1 < firstRow ) {
      // before first non-empty row
      return new KCell[0];
    }
    if ( rownr > 0 && currentRow == rownr + 1 ) {
      if ( currentRowCells != null ) {
        return currentRowCells;
      }
      // The case when the table contains the empty row(s) before the header
      // but at the same time user wants to read starting from 0 row
      return new KCell[0];
    }
    try {
      if ( currentRow >= rownr + 1 ) {
        // allow random access per api despite performance hit
        resetSheetReader();
      }

View on GitHub (pinned to f3058517a1)