pentaho/pentaho-kettle · error · IllegalArgumentException
The date has too much day from epoch day!
Error message
The date has too much day from epoch day!
What it means
During Avro record creation, converting a Kettle date/timestamp field to an Avro epoch-day value triggers an ArithmeticException (integer overflow in day computation), which createAvroRecord wraps as IllegalArgumentException('The date has too much day from epoch day!'). It signals a date value too extreme to represent as an Avro date.
Solutions
- Inspect the offending row's date value and fix it upstream (correct year/epoch unit)
- Verify the field's Avro logical type mapping (date vs timestamp-millis) matches the Kettle value type
- Add a filter/invalid-rows handling step before the Avro output to divert rows with out-of-range dates
- Catch IllegalArgumentException from write() and log the row for correction
Example fix
// before
row.getDate( "event_date" ) // contains year 999999999 -> ArithmeticException on toEpochDay()
// after
// sanitize/validate before writing
LocalDate d = row.getDate( "event_date" ).toInstant().atZone( ZoneOffset.UTC ).toLocalDate();
if ( d.getYear() < 1 || d.getYear() > 9999 ) { d = LocalDate.of( 9999, 12, 31 ); } Defensive patterns
Strategy: validation
Validate before calling
Date d = row.getDate( fieldName );
long year = d == null ? 0 : d.toInstant().atZone( ZoneOffset.UTC ).getYear();
if ( year < 1 || year > 9999 ) {
throw new ValidationException( fieldName + " year out of representable range: " + year );
} Try / catch
try {
writer.write( row );
} catch ( IllegalArgumentException e ) {
logError( "Unwritable date row: " + e.getMessage(), e );
// route row to error stream
} Prevention
- Validate date ranges in input data before Avro output
- Keep epoch units consistent (seconds vs milliseconds)
- Match Avro logical types (date/timestamp-millis) to Kettle value types
- Use a filter step to divert rows with implausible dates
When it happens
Trigger: Writing a row whose date/timestamp field, when converted to epoch days (long/days conversion in the field-mapping switch), overflows — e.g. a year like 999999999 or a null-parsed garbage value producing a huge millisecond count.
Common situations: Bad input data in a date column (typo'd year, sentinel dates like 0001-01-01 mishandled, epoch in wrong unit — seconds passed as milliseconds); inconsistent source-type mapping between timestamp and date fields.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- some exception while writing avro
- Argument of TRUNC of date has to be between 0 and 5
- Argument of TRUNC of date has to be between 0 and 5
- AvroInput.Error.UnexpectedArrayElementTypeAtNonExpansionPoin…
- AvroInput.Error.CantLoadIncommingSchemaAndNoDefault
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/768f0f732f0c44f6.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/avro-format/core/src/main/java/org/pentaho/di/trans/steps/avro/output/PentahoAvroRecordWriter.java:225
case TIMESTAMP_MILLIS, TIMESTAMP_MICROS, TIMESTAMP_NANOS:
Timestamp defaultTimestamp = null;
if ( defaultValue != null && !defaultValue.isEmpty() ) {
String conversionMask =
( vmi.getConversionMask() == null ) ? ValueMetaBase.DEFAULT_TIMESTAMP_PARSE_MASK
: vmi.getConversionMask();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern( conversionMask );
LocalDateTime ldt = LocalDateTime.parse( defaultValue, fmt );
defaultTimestamp = Timestamp.valueOf( ldt );
}
Timestamp timeStamp = (Timestamp) row.getDate( fieldMetaIndex, defaultTimestamp );
outputRecord.put( avroFieldName, AvroTimestampHandler.fromTimestamp( timeStamp, avroType ) );
break;
}
}
}
} catch ( ArithmeticException e ) {
throw new IllegalArgumentException( "The date has too much day from epoch day!", e );
} catch ( KettleValueException e ) {
throw new IllegalArgumentException( "some exception while writing avro", e );
}
return outputRecord;
}
private double applyScale( double number, IAvroOutputField outputField ) {
if ( outputField.getScale() > 0 ) {
BigDecimal bd = new BigDecimal( number );
bd = bd.setScale( outputField.getScale(), BigDecimal.ROUND_HALF_UP );
number = bd.doubleValue();
}
return number;
}
private float applyScale( float number, IAvroOutputField outputField ) {
if ( outputField.getScale() > 0 ) {
BigDecimal bd = new BigDecimal( number );View on GitHub (pinned to f3058517a1)