pentaho/pentaho-kettle · error · RuntimeException

start smaller than 0

Error message

start smaller than 0

What it means

Explicit validation inside the 3-argument substr() helper: the start index (ArgList[1], rounded to int) must not be negative. Unlike real JavaScript substr(), which treats negative starts as offsets from the end, this Java-backed implementation rejects them.

Solutions

  1. Clamp the start: if (start < 0) start = 0; before calling substr.
  2. Compute indexOf results defensively: var idx = str.indexOf('x'); var start = idx < 0 ? 0 : idx.
  3. To emulate negative-from-end, translate yourself: substr(str, str.length + negStart, len) when str.length + negStart >= 0.
  4. Clamp the translated start to 0 as well, since length+neg can still be negative.

Example fix

// before
var s = substr(str, -3, 3);
// after
var start = str.length - 3; if (start < 0) start = 0; var s = substr(str, start, 3);
Defensive patterns

Strategy: validation

Validate before calling

var start = Number(fromExpr); if (!(start >= 0)) start = 0; var s = substr(str, start, len);

Type guard

function hasValidStart(start){ return typeof start === 'number' && isFinite(start) && start >= 0; }

Try / catch

try { s = substr(str, start, len); } catch (e) { if (/start smaller than 0/.test(e.message)) s = ''; else throw e; }

Prevention

When it happens

Trigger: Calling substr(str, -N, len) or substr(str, someNegativeVar, len); notably porting JavaScript substr code that relied on negative start-from-end semantics.

Common situations: Migrating browser/Rhino-native substr logic into the Kettle JavaScript step; computing the start index with arithmetic that can go below zero (e.g. indexOf returning -1).

Related errors


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

Appendix: source

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

      } catch ( Exception e ) {
        throw new RuntimeException( "The function call substr is not valid : " + e.getMessage() );
      }
    } else if ( ArgList.length == 3 ) {
      try {
        int to;
        int strLen;

        if ( isNull( ArgList[0] ) ) {
          return null;
        } else if ( isUndefined( ArgList[0] ) ) {
          return (String) undefinedValue;
        }
        sRC = (String) ArgList[0];
        int from = (int) Math.round( (Double) ArgList[1] );
        int len = (int) Math.round( (Double) ArgList[2] );

        if ( from < 0 ) {
          throw new RuntimeException( "start smaller than 0" );
        }
        if ( len < 0 ) {
          len = 0; // Make it compatible with Javascript substr
        }

        to = from + len;
        strLen = sRC.length();
        if ( to > strLen ) {
          to = strLen;
        }
        sRC = sRC.substring( from, to );
      } catch ( Exception e ) {
        throw new RuntimeException( "The function call substr is not valid : " + e.getMessage() );
      }
    } else {
      throw new RuntimeException( "The function call substr requires 2 or 3 arguments." );
    }
    return sRC;

View on GitHub (pinned to f3058517a1)