pentaho/pentaho-kettle · error · RuntimeException

Locale " + sArg3 + " is not 2 characters long.

Error message

Locale " + sArg3 + " is not 2 characters long.

What it means

Thrown by the str2date JavaScript function implementation in ScriptAddedFunctions when the third argument (a locale code) is not exactly 2 characters long. The library requires a 2-letter language code (e.g. "en", "de") to build a java.util.Locale via EnvUtil.createLocale before constructing a SimpleDateFormat. It fails fast with this message rather than passing a malformed locale to the JDK.

Solutions

  1. Pass a 2-letter language code as the third argument, e.g. str2date(str,'yyyy/MM/dd','en') instead of 'en_US'.
  2. Strip a regional suffix before calling: locale.substring(0,2) if the value looks like 'en_US'.
  3. Verify the variable/field feeding the locale argument is populated and exactly 2 characters.
  4. If you need locale+country behavior, note this API only accepts the language code; pre-normalize or use a different parsing approach.

Example fix

// before (JS in a Modified Java Script Value step)
var d = str2date('2024-01-01', 'yyyy-MM-dd', 'en_US');
// after
var d = str2date('2024-01-01', 'yyyy-MM-dd', 'en');
Defensive patterns

Strategy: validation

Validate before calling

function validLocaleArg(loc) { return typeof loc === 'string' && loc.length === 2; }
if (!validLocaleArg(loc)) throw new Error('locale must be a 2-letter code, got: ' + loc);

Type guard

function isTwoLetterLocale(v) { return typeof v === 'string' && /^[a-zA-Z]{2}$/.test(v); }

Try / catch

try { var d = str2date(s, fmt, loc); } catch (e) { if (String(e.message).indexOf('is not 2 characters long') >= 0) { loc = String(loc).substring(0,2); d = str2date(s, fmt, loc); } else { throw e; } }

Prevention

When it happens

Trigger: Calling str2date(dateString, format, locale) in a JavaScript (Rhino/JS) script step where ArgList[2] has length != 2, e.g. str2date('2024/01/01','yyyy/MM/dd','en_US') or 'enu' or '' or null-length strings.

Common situations: Developers copy full BCP-47 tags like 'en-US' or 'en_US' instead of the 2-letter language code; they pass a country code ('US') or a 3-letter code ('eng'); the value comes from a variable/field that is empty or null.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/script/ScriptAddedFunctions.java:1044

        }
        break;
      case 3:
        try {
          if ( isNull( ArgList, new int[] { 0, 1, 2 } ) ) {
            return null;
          } else if ( isUndefined( ArgList, new int[] { 0, 1, 2 } ) ) {
            return undefinedValue;
          }
          sArg1 = (String) ArgList[0];
          Format dfFormatter;
          sArg2 = (String) ArgList[1];
          sArg3 = (String) ArgList[2];
          if ( sArg3.length() == 2 ) {
            Locale dfLocale = EnvUtil.createLocale( sArg3 );
            dfFormatter = new SimpleDateFormat( sArg2, dfLocale );
            oRC = dfFormatter.parseObject( sArg1 );
          } else {
            throw new RuntimeException( "Locale " + sArg3 + " is not 2 characters long." );
          }
        } catch ( Exception e ) {
          throw new RuntimeException( "Could not apply the local format for locale "
            + sArg3 + " with the given format " + sArg2 + " on the string for " + sArg1 + " : " + e.getMessage() );
        }
        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 undefinedValue;
          }
          sArg1 = (String) ArgList[0];
          DateFormat dfFormatter;
          sArg2 = (String) ArgList[1];
          sArg3 = (String) ArgList[2];
          sArg4 = (String) ArgList[3];

View on GitHub (pinned to f3058517a1)