pentaho/pentaho-kettle · error · JavaScriptException

Could not convert to the given local format.

Error message

Could not convert to the given local format.

What it means

This error is thrown by the date2str JavaScript function in ScriptValuesAddedFunctions when formatting a Date with an explicit locale fails. The 3-argument form builds a SimpleDateFormat with a user-supplied pattern and a 2-letter locale string; any exception in that path (bad pattern, bad locale, wrong argument types) is caught and re-thrown as this generic runtime error. It deliberately masks the underlying exception, so the real cause must be inferred from the arguments.

Solutions

  1. Validate the pattern with Java's SimpleDateFormat outside the script (new SimpleDateFormat(pattern, locale)) to see the real underlying exception.
  2. Ensure the first argument is a Date (use new Date(...) or d2i/date parsing first) and not null/undefined.
  3. Use a 2-letter ISO-639 locale code (e.g. 'de', 'fr'); longer codes are rejected before this path.
  4. Quote literal characters in the pattern with single quotes (e.g. "yyyy-MM-dd'T'HH:mm:ss").

Example fix

// before
date2str(orderDate, "yyyy-mm-dd hh:mm:ss", "en_US")
// after
date2str(orderDate, "yyyy-MM-dd HH:mm:ss", "en")
Defensive patterns

Strategy: validation

Validate before calling

// JS in Kettle step
function safeDate2str(d, fmt, loc) {
  if (d == null || fmt == null || loc == null || loc.length != 2) return null;
  return date2str(d, fmt, loc);
}

Type guard

function isDate(v) { return v != null && typeof v.getTime === 'function'; }

Try / catch

try { result = date2str(d, fmt, loc); } catch (e) { result = null; /* log e for step failure diagnostics */ }

Prevention

When it happens

Trigger: Calling date2str(date, pattern, locale) in a Kettle/JavaScript step where: the pattern contains illegal SimpleDateFormat characters (e.g. "yyyy-mm-dd" intended but with unquoted literals like 'T' handled wrong, or stray quotes), the locale argument is not exactly 2 characters (which first raises the 2-char check only when the check branch is reached; other arg-shape failures land here), the first argument is not a Date/number, or the arguments are null/undefined so SimpleDateFormat construction throws.

Common situations: Transformation developers passing a string timestamp instead of a Date object; using locale codes like 'en_US' (5 chars) instead of 'en'; typos in the format mask such as unmatched single quotes; migrating scripts between Kettle versions where date2str argument order or null handling changed.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/scriptvalues_mod/ScriptValuesAddedFunctions.java:1178

        try {
          if ( isNull( ArgList, new int[] { 0, 1, 2 } ) ) {
            return null;
          } else if ( isUndefined( ArgList, new int[] { 0, 1, 2 } ) ) {
            return Context.getUndefinedValue();
          }
          java.util.Date dArg1 = (java.util.Date) Context.jsToJava( ArgList[0], java.util.Date.class );
          DateFormat dfFormatter;
          String sArg2 = Context.toString( ArgList[1] );
          String sArg3 = Context.toString( ArgList[2] );
          if ( sArg3.length() == 2 ) {
            Locale dfLocale = EnvUtil.createLocale( sArg3.toLowerCase() );
            dfFormatter = new SimpleDateFormat( sArg2, dfLocale );
            oRC = dfFormatter.format( dArg1 );
          } else {
            throw Context.reportRuntimeError( "Locale is not 2 characters long." );
          }
        } catch ( Exception e ) {
          throw Context.reportRuntimeError( "Could not convert to the given local format." );
        }
        break;
      case 4:
        try {
          if ( isNull( ArgList, new int[] { 0, 1, 2, 3 } ) ) {
            return null;
          } else if ( isUndefined( ArgList, new int[] { 0, 1, 2, 3 } ) ) {
            return Context.getUndefinedValue();
          }
          java.util.Date dArg1 = (java.util.Date) Context.jsToJava( ArgList[0], java.util.Date.class );
          DateFormat dfFormatter;
          String sArg2 = Context.toString( ArgList[1] );
          String sArg3 = Context.toString( ArgList[2] );
          String sArg4 = Context.toString( ArgList[3] );

          // If the timezone is not recognized, java will automatically
          // take GMT.
          TimeZone tz = TimeZone.getTimeZone( sArg4 );

View on GitHub (pinned to f3058517a1)