pentaho/pentaho-kettle · error · KettleException

PGBulkLoader doesn't know how to handle date (neither…

Error message

PGBulkLoader doesn't know how to handle date (neither passthrough, nor date or datetime for field 

What it means

When writing a row field of type Date to the COPY stream, writeRowToPostgres switches on data.dateFormatChoices[i]; the default branch fires when the date format choice is none of passthrough/date/datetime. This is an internal configuration mismatch for that field's date handling.

Solutions

  1. Open the step's Fields tab and explicitly set a Date format (Date mask) for every date field, then re-save
  2. Inspect the saved transformation/repo metadata for the field's date_mask value and correct it to a recognized value
  3. Recreate the field mapping with 'Get Fields' so defaults are applied cleanly
  4. Patch PGBulkLoaderMeta.readData/readRep handling so unknown masks fall back to a valid default instead of producing an unmapped choice

Example fix

// before (unmapped mask)
dateMask[i] = "weird_mask"; // -> dateFormatChoices[i] hits default
// after
meta.setDateMask( i, PGBulkLoaderMeta.getDateMaskDefault() ); // recognized constant
Defensive patterns

Strategy: validation

Validate before calling

// verify each date field has a recognized mask in the saved meta
for ( int i = 0; i < meta.getFieldStream().length; i++ ) {
  String mask = meta.getFieldDateMask()[i];
  if ( mask == null || !List.of( "Pass through", "Date mask", "DateTime mask" ).contains( mask ) ) {
    throw new IllegalStateException( "Unrecognized date mask for field " + meta.getFieldStream()[i] );
  }
}

Try / catch

try {
  step.processRow();
} catch ( KettleException e ) {
  if ( e.getMessage().contains( "doesn't know how to handle date" ) ) {
    // reconfigure the date mask for the named field
  }
}

Prevention

When it happens

Trigger: A field of ValueMetaInterface.TYPE_DATE reaches writeRowToPostgres while its entry in data.dateFormatChoices was never initialized to one of the supported choices (passthrough, date, datetime), e.g. meta loaded from an unrecognized/empty date_mask value.

Common situations: Older or hand-edited transformation XML where the date mask attribute is missing or has an unexpected value; repository record with a corrupted date_mask string; version upgrade changing the recognized mask constants so a stored value no longer maps to a choice.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at plugins/postgresql-db-bulk-loader/impl/src/main/java/org/pentaho/di/trans/steps/pgbulkloader/PGBulkLoader.java:354

                //
                case PGBulkLoaderMeta.NR_DATE_MASK_DATE:
                  String dateString = data.dateMeta.getString( valueMeta.getDate( valueData ) );
                  if ( dateString != null ) {
                    pgCopyOut.write( dateString.getBytes( clientEncoding ) );
                  }
                  break;

                // Convert to a "YYYY-MM-DD HH:MM:SS.mmm" format
                //
                case PGBulkLoaderMeta.NR_DATE_MASK_DATETIME:
                  String dateTimeString = data.dateTimeMeta.getString( valueMeta.getDate( valueData ) );
                  if ( dateTimeString != null ) {
                    pgCopyOut.write( dateTimeString.getBytes( clientEncoding ) );
                  }
                  break;

                default:
                  throw new KettleException( "PGBulkLoader doesn't know how to handle date (neither passthrough, nor date or datetime for field " + valueMeta.getName() );
              }
              break;
            case ValueMetaInterface.TYPE_TIMESTAMP:
              // Format the date in the right format.
              //
              switch ( data.dateFormatChoices[i] ) {
              // Pass the data along in the format chosen by the user OR in binary format...
              //
                case PGBulkLoaderMeta.NR_DATE_MASK_PASS_THROUGH:
                  if ( valueMeta.isStorageBinaryString() ) {
                    pgCopyOut.write( (byte[]) valueData );
                  } else {
                    String dateString = valueMeta.getString( valueData );
                    if ( dateString != null ) {
                      pgCopyOut.write( dateString.getBytes( clientEncoding ) );
                    }
                  }
                  break;

View on GitHub (pinned to f3058517a1)