pentaho/pentaho-kettle · error · RuntimeException
Endless loop detected for substitution of variable:
Error message
Endless loop detected for substitution of variable:
What it means
StringUtil.substitute (variable substitution engine) throws a RuntimeException when the recursion depth of variable replacement exceeds 50, meaning a variable value references itself directly or through a cycle (e.g. A=${B}, B=${A}). The guard prevents infinite recursion / stack overflow.
Solutions
- Find the self-referencing or circular variable (the name is appended to the message) and break the cycle.
- Rename the intermediate variables so each value references only other, non-circular variables.
- Pre-resolve the variable value and store the literal result instead of a placeholder containing itself.
- Audit kettle.properties, system properties and transformation/job parameters for repeated variable names.
Example fix
// before
props.setProperty("JAVA_HOME", "${JAVA_HOME}/jdk11");
// after
props.setProperty("JAVA_HOME_PARENT", "/opt/java");
props.setProperty("JAVA_HOME", "${JAVA_HOME_PARENT}/jdk11"); Defensive patterns
Strategy: validation
Validate before calling
// detect self-reference before substitution
String v = variables.getVariable("VAR_A");
if (v != null && v.contains("${VAR_A}")) throw new KettleException("VAR_A references itself"); Try / catch
try {
result = StringUtil.environmentSubstitute(raw);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Endless loop detected")) {
throw new KettleException("Circular variable definition: " + e.getMessage(), e);
}
throw e;
} Prevention
- Never define a variable whose value contains its own placeholder.
- Keep variable chains short and review kettle.properties after merges.
- Unit-test variable substitution graphs for cycles.
When it happens
Trigger: A kettle.properties / environment variable whose value contains a reference to itself, or a circular chain of variable references like VAR_A=${VAR_B} and VAR_B=${VAR_A}, expanded via StringUtil.environmentSubstitute / substitute with ${...} (or custom open/close delimiters).
Common situations: Setting VAR_HOME=${VAR_HOME}/sub in kettle.properties or a transformation-level parameter referencing itself; copying variables between environments where one was previously resolved and re-registered including its own placeholder.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- ChangeFileEncoding.Exception.TargetEncodingEmpty
- FileSystemConfigBuilder could not parse parameter:
- JobJobError.Recursive
- Please specify Local directory
- Variable '" + Const.INTERNAL_VARIABLE_SLAVE_SERVER_NAME +…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/0dfeef6110de6002.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/util/StringUtil.java:152
if ( j > -1 ) {
String varName = rest.substring( i + open.length(), j );
Object value = variablesValues.get( varName );
if ( value == null ) {
value = open + varName + close;
} else if ( aString.equals( value ) ) {
//Needed to avoid an endless loop if left to continue to next else statement
return (String) value;
} else {
// check for another variable inside this value
int another = ( (String) value ).indexOf( open ); // check
// here
// first for
// speed
if ( another > -1 ) {
// for safety: avoid recursive
if ( recursion > 50 ) {
// endless loops with stack overflow
throw new RuntimeException( "Endless loop detected for substitution of variable: " + (String) value );
}
value = substitute( (String) value, variablesValues, open, close, ++recursion );
}
}
buffer.append( rest.substring( 0, i ) );
buffer.append( value );
rest = rest.substring( j + close.length() );
} else {
// no closing tag found; end the search
buffer.append( rest );
rest = "";
}
// keep searching
i = rest.indexOf( open );
}
buffer.append( rest );
return buffer.toString();
}View on GitHub (pinned to f3058517a1)