pentaho/pentaho-kettle · error · KettleValueException

<toString()> : couldn't convert string

Error message

<toString()> : couldn't convert string [<string>] to a date using format [<dateFormat>] on offset location <e.getErrorOffset()>

What it means

Thrown by ValueMetaBase.convertStringToDate when SimpleDateFormat.parse fails to parse the string using the value meta's date format. The message includes the value meta name, the offending string, the format pattern, and the character offset where parsing failed.

Solutions

  1. Set the correct conversion mask with setConversionDateFormat or getDateFormat matching the actual string (e.g. 'dd/MM/yyyy HH:mm:ss')
  2. Check the sample string against the pattern at the reported error offset
  3. Set the correct locale/timezone on the value meta (setDateFormatLocale/setDateFormatTimeZone)
  4. Pre-validate the string with a DateTimeFormatter before calling getDate

Example fix

// before
valueMeta.setConversionMask("yyyy-MM-dd"); // data is 25/03/1918 11:54
// after
valueMeta.setConversionMask("dd/MM/yyyy HH:mm");
Defensive patterns

Strategy: validation

Validate before calling

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.LocalDateTime;
static boolean isParseableDate(String s, String pattern) {
  try {
    DateTimeFormatter.ofPattern(pattern).parse(s);
    return true;
  } catch (DateTimeParseException | NullPointerException e) {
    return false;
  }
}

Type guard

static boolean looksLikeDate(String s, String patternRegex) {
  return s != null && !s.trim().isEmpty() && s.matches(patternRegex);
}

Try / catch

try {
  Date d = valueMeta.getDate(str);
} catch (KettleValueException e) {
  log.error("Date parse failed: " + e.getMessage());
  putRowToErrorRow(str, e.getMessage());
}

Prevention

When it happens

Trigger: Calling getDate()/convertStringToDate() on a String value that does not match getDateFormat().toPattern(); a null format (shown as 'null') with a non-default-parseable string; locale-sensitive patterns applied to strings produced under a different locale/timezone.

Common situations: Missing or wrong conversion mask (e.g. 'yyyy-MM-dd' vs 'dd/MM/yyyy'); data files changing date format after an upstream change; strings with trailing characters or empty input; parsing '25-03-1918 11:54' with a date-only format.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/row/value/ValueMetaBase.java:936

    if ( Utils.isEmpty( string ) ) {
      return null;
    }

    try {
      ParsePosition pp = new ParsePosition( 0 );
      Date result = getDateFormat( TYPE_DATE ).parse( string, pp );
      if ( pp.getErrorIndex() >= 0 ) {
        // error happen
        throw new ParseException( string, pp.getErrorIndex() );
      }
      // some chars can be after pp.getIndex(). That means, not full value was parsed. For example, for value
      // "25-03-1918 11:54" and format "dd-MM-yyyy", value will be "25-03-1918 00:00" without any exception.
      // If there are only spaces after pp.getIndex() - that means full values was parsed
      return result;
    } catch ( ParseException e ) {
      String dateFormat = ( getDateFormat() != null ) ? getDateFormat().toPattern() : "null";
      throw new KettleValueException( toString() + " : couldn't convert string [" + string
          + "] to a date using format [" + dateFormat + "] on offset location " + e.getErrorOffset(), e );
    }
  }

  // DATE + NUMBER

  protected Double convertDateToNumber( Date date ) {
    return new Double( date.getTime() );
  }

  protected Date convertNumberToDate( Double number ) {
    return new Date( number.longValue() );
  }

  // DATE + INTEGER

  protected Long convertDateToInteger( Date date ) {
    return new Long( date.getTime() );

View on GitHub (pinned to f3058517a1)