pentaho/pentaho-kettle · error · KettleException

e.getMessage() (first conversion cause, no own message)

Error message

e.getMessage() (first conversion cause, no own message)

What it means

When the CSV input step's KettleCSVException carries multiple causes, processRow normally reports them via putError; if error handling is not enabled (or only-forward mode), it rethrows a KettleException with e.getMessage() and only the FIRST cause, dropping the rest.

Solutions

  1. Look at e.getCauses().get(0) (the chained cause) for the first concrete failure
  2. Enable the step's error handling so all causes are captured via putError instead of thrown
  3. Fix the data or field formats causing the parse failures
  4. If several rows are bad, run with error-handling to collect the full list
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate a sample CSV row against declared field formats
for (int i = 0; i < fields.length; i++)
  fields[i].meta.convertData(fields[i].meta, sample[i]); // throws early

Try / catch

try { processRow(...); }
catch (KettleException e) { logError("First CSV failure: " + e.getCause().getMessage(), e.getCause()); }

Prevention

When it happens

Trigger: processRow hits a row-level parsing/conversion failure while error handling (putError) is unavailable, e.g. during unit-style invocations like testFileIsReleasedAfterProcessing.

Common situations: Malformed CSV rows with mixed type failures, running the step in tests without an error-handling row set, files with inconsistent column types.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/csvinput/CsvInput.java:182

      if ( getStepMeta().isDoingErrorHandling() ) {
        StringBuilder errorDescriptions = new StringBuilder( 100 );
        StringBuilder errorFields = new StringBuilder( 50 );
        for ( int i = 0; i < e.getCauses().size(); i++ ) {
          if ( i > 0 ) {
            errorDescriptions.append( ", " );
            errorFields.append( ", " );
          }
          errorDescriptions.append( e.getCauses().get( i ).getMessage() );
          errorFields.append( e.getFields().get( i ).toStringMeta() );
        }

        putError(
          data.outputRowMeta, e.getRowData(), e.getCauses().size(), errorDescriptions.toString(), errorFields
            .toString(), "CSVINPUT001" );
      } else {
        // Only forward the first cause.
        //
        throw new KettleException( e.getMessage(), e.getCauses().get( 0 ) );
      }
    }

    return true;
  }

  private void prepareToRunInParallel() throws KettleException {
    try {
      // At this point it doesn't matter if we have 1 or more files.
      // We'll use the same algorithm...
      //
      for ( String filename : data.filenames ) {
        long size = KettleVFS.getInstance( getTransMeta().getBowl() )
          .getFileObject( filename, getTransMeta() ).getContent().getSize();
        data.fileSizes.add( size );
        data.totalFileSize += size;
      }

View on GitHub (pinned to f3058517a1)