pentaho/pentaho-kettle · error · KettleException
MergeRows.Exception.InvalidLayoutDetected
MergeRows.Exception.InvalidLayoutDetected
Error message
MergeRows.Exception.InvalidLayoutDetected
What it means
Thrown by the Merge Rows step in processRow when checkInputLayoutValid detects that the reference and compare input streams do not have identical row layouts (same fields, same order/types). Since the message wraps the original KettleRowException, the cause describes the exact mismatch. Merge Rows requires both streams to be structurally identical to compare them.
Solutions
- Read the wrapped cause (getCause()) — checkInputLayoutValid's message names the exact field/type/order mismatch.
- Preview both input streams and align their field layouts exactly (same fields, same order, same types).
- Add a 'Select values' step on each branch to add/rename/reorder fields and convert types so both layouts match.
- Use the step's Check/validate feature or the transformation validator before running.
Example fix
// before: compare stream missing 'updated_date' reference: [id, name, updated_date] compare: [id, name] // after: add Select values step on compare branch to include updated_date (Date) compare: [id, name, updated_date]
Defensive patterns
Strategy: validation
Validate before calling
// Java: compare the two input layouts before running
StepMeta mergeRows = transMeta.findStep("Merge Rows");
RowMetaInterface ref = transMeta.getPrevStepFields(mergeRows, 0);
RowMetaInterface cmp = transMeta.getPrevStepFields(mergeRows, 1);
if (!ref.equals(cmp)) {
throw new IllegalStateException("Merge Rows input layouts differ");
} Try / catch
try {
trans.execute(null);
} catch (KettleException e) {
if (e.getMessage().contains("InvalidLayoutDetected")) {
// inspect e.getCause() (KettleRowException) for the exact field mismatch
}
} Prevention
- Keep both branches structurally identical: same fields, order, and types.
- Insert 'Select values' steps after any branch that alters the layout.
- Preview both inputs after every upstream change.
- Validate the transformation before production runs.
When it happens
Trigger: processRow fetches one row from each input row set and calls checkInputLayoutValid(data.oneRowSet.getRowMeta(), data.twoRowSet.getRowMeta()); any layout difference (missing field, different type, different field order) throws KettleRowException, which is rethrown as this KettleException.
Common situations: See trigger scenarios.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- MergeRows.Exception.UnableToFindFieldInReferenceStream
- MergeRowsMeta.Exception.FlagFieldNotSpecified
- AnalyticQueryMeta.Exception.SubjectFieldNotFound
- BaseStep.SafeMode.Exception.DoubleFieldnames
- BaseStep.SafeMode.Exception.MixingLayout
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/8a674fb66bb43bfd.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/mergerows/MergeRows.java:93
//rowSetWhenIdentical is use in case the comparison is IDENTICAL.
//this should be the "Comparison" stream but can be the "Reference" stream for backward compatibility (PDI-736)
String useRefWhenIdenticalVar = Const
.NVL( System.getProperty( Const.KETTLE_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL ), "N" );
if ( "N".equalsIgnoreCase( useRefWhenIdenticalVar ) ) {
//use the reference stream (as per documentation)
useRefWhenIdentical = false;
} else {
//use the comparison stream (for backward compatibility)
useRefWhenIdentical = true;
}
data.one = getRowFrom( data.oneRowSet );
data.two = getRowFrom( data.twoRowSet );
try {
checkInputLayoutValid( data.oneRowSet.getRowMeta(), data.twoRowSet.getRowMeta() );
} catch ( KettleRowException e ) {
throw new KettleException( BaseMessages.getString( PKG, "MergeRows.Exception.InvalidLayoutDetected" ), e );
}
if ( data.one != null ) {
// Find the key indexes:
data.keyNrs = new int[ meta.getKeyFields().length ];
for ( int i = 0; i < data.keyNrs.length; i++ ) {
data.keyNrs[ i ] = data.oneRowSet.getRowMeta().indexOfValue( meta.getKeyFields()[ i ] );
if ( data.keyNrs[ i ] < 0 ) {
String message =
BaseMessages.getString( PKG, "MergeRows.Exception.UnableToFindFieldInReferenceStream", meta
.getKeyFields()[ i ] );
logError( message );
throw new KettleStepException( message );
}
}
}
if ( data.two != null ) {View on GitHub (pinned to f3058517a1)