pentaho/pentaho-kettle · error · RuntimeException
infinite loop detected: + key
Error message
infinite loop detected: + key
What it means
ClosureGenerator.recurseParents walks the parent map building the closure table. As a safeguard against cyclic parent-child data, it throws a RuntimeException when recursion depth exceeds 50. It means the hierarchy data contains a cycle (a row's ancestry loops back on itself) rather than forming a tree.
Solutions
- Find and fix the cycle in the source data (detect rows whose parent chain loops)
- Filter or flag self-referencing rows before the step
- Pre-validate the hierarchy in a prior step or with a SQL cycle check
- If legitimately deeper than 50 levels, adjust the hardcoded depth guard in a patched build
Example fix
// before (bad data) row: id=A, parent=B; id=B, parent=A // after row: id=B, parent=null (break the cycle at the root)
Defensive patterns
Strategy: validation
Validate before calling
-- SQL cycle pre-check before the step WITH RECURSIVE chain(id, parent, depth) AS ( SELECT id, parent_id, 0 FROM tree UNION ALL SELECT t.id, t.parent_id, c.depth+1 FROM tree t JOIN chain c ON t.parent_id = c.id WHERE depth < 60 ) SELECT id FROM chain WHERE depth > 50;
Type guard
boolean isAcyclic(Map<Object,Object> parentMap) {
for (Object k : parentMap.keySet()) {
int d = 0; Object cur = k;
while (cur != null && d <= 50) { cur = parentMap.get(cur); d++; }
if (d > 50) return false;
}
return true;
} Try / catch
try {
step.processRow();
} catch (RuntimeException e) {
if (e.getMessage().startsWith("infinite loop detected")) {
// cycle in hierarchy data; identify the key from the message and fix source rows
}
} Prevention
- Enforce referential constraints on hierarchy tables
- Reject self-referencing rows in upstream steps
- Log the offending key to locate the cycle
When it happens
Trigger: Processing input rows where a record is its own ancestor — e.g. rows A->B, B->C, C->A — causing the recursive parent lookup to never terminate.
Common situations: Dirty hierarchical data (employee-manager cycles), self-referencing rows (A->A), importing hierarchies from systems without referential constraints.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- ChangeFileEncoding.Error.SourceFileIsEmpty
- Endless loop detected for substitution of variable:
- JobJobError.Recursive
- PGPEncryptStream.Error.DataToEncryptEmpty
- some exception while writing avro
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/6fa9c4208ca56a04.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/core/impl/src/main/java/org/pentaho/di/trans/steps/closure/ClosureGenerator.java:116
Object[] outputRow = RowDataUtil.allocateRowData( data.outputRowMeta.size() );
outputRow[ 0 ] = parent;
outputRow[ 1 ] = current;
outputRow[ 2 ] = data.parents.get( parent );
putRow( data.outputRowMeta, outputRow );
}
}
setOutputDone();
return false;
}
return true;
}
private void recurseParents( Object key, long distance ) {
// catch infinite loop - change at will
if ( distance > 50 ) {
throw new RuntimeException( "infinite loop detected:" + key );
}
Object parent = data.map.get( key );
if ( parent == null || parent == data.topLevel || parent.equals( data.topLevel ) ) {
return;
} else {
data.parents.put( parent, distance );
recurseParents( parent, distance + 1 );
return;
}
}
public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
meta = (ClosureGeneratorMeta) smi;
data = (ClosureGeneratorData) sdi;
if ( super.init( smi, sdi ) ) {
data.reading = true;View on GitHub (pinned to f3058517a1)