pentaho/pentaho-kettle · error · ArrayIndexOutOfBoundsException

Read beyond last row: " + rownr

Error message

Read beyond last row: " + rownr

What it means

OdfSheet.getRow(int rownr) throws an ArrayIndexOutOfBoundsException with the message 'Read beyond last row: <rownr>' when the requested row index is greater than or equal to the sheet's row count. It is a bounds check protecting downstream access to the ODF table, which would otherwise fail less clearly.

Solutions

  1. Query the sheet's row count first and loop only up to it (e.g. for (int i = 0; i < sheet.getRows(); i++)).
  2. Validate the expected row count against the actual file before processing.
  3. Catch ArrayIndexOutOfBoundsException around row access and treat it as end-of-data if iterating speculatively.
  4. Re-open the workbook to refresh nrOfRows if the file was modified externally.

Example fix

// before
for (int r = 0; r < expectedRows; r++) { KCell[] row = sheet.getRow(r); }
// after
int rows = Math.min(expectedRows, sheet.getRows());
for (int r = 0; r < rows; r++) { KCell[] row = sheet.getRow(r); }
Defensive patterns

Strategy: validation

Validate before calling

if (rownr >= 0 && rownr < sheet.getRows()) { KCell[] row = sheet.getRow(rownr); }

Try / catch

try { KCell[] row = sheet.getRow(rownr); } catch (ArrayIndexOutOfBoundsException e) { row = new KCell[0]; // treat as end-of-data }

Prevention

When it happens

Trigger: Calling OdfSheet.getRow() (or the KSheet.row() wrapper that delegates to it) with a rownr >= nrOfRows, typically by iterating a fixed row count larger than the actual sheet contents.

Common situations: Hard-coding a row count from a stale preview; looping rows without checking sheet.getRows(); a data file truncated or regenerated with fewer rows since the transform was configured.

Related errors


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

Appendix: source

Thrown at plugins/excel/core/src/main/java/org/pentaho/di/trans/steps/excelinput/ods/OdfSheet.java:116

              result -= ( (TableTableCellElement) cell ).getTableNumberColumnsRepeatedAttribute();
            } else {
              // get first non-empty cell from the end, break
              break;
            }
          }
        }
      }
    }
    return result;
  }

  public String getName() {
    return table.getTableName();
  }

  public KCell[] getRow( int rownr ) {
    if ( rownr >= nrOfRows ) {
      throw new ArrayIndexOutOfBoundsException( "Read beyond last row: " + rownr );
    }
    OdfTableRow row = table.getRowByIndex( rownr );
    int cols = findNrColumns( row );
    OdfCell[] xlsCells = new OdfCell[ cols ];
    for ( int i = 0; i < cols; i++ ) {
      OdfTableCell cell = row.getCellByIndex( i );
      if ( cell != null ) {
        xlsCells[i] = new OdfCell( cell );
      }
    }
    return xlsCells;
  }

  public int getRows() {
    return nrOfRows;
  }

  public KCell getCell( int colnr, int rownr ) {

View on GitHub (pinned to f3058517a1)