{"record":{"id":"8a674fb66bb43bfd","repo":"pentaho/pentaho-kettle","slug":"mergerows-exception-invalidlayoutdetected","errorCode":"MergeRows.Exception.InvalidLayoutDetected","errorMessage":"MergeRows.Exception.InvalidLayoutDetected","messagePattern":"MergeRows\\.Exception\\.InvalidLayoutDetected","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/mergerows/MergeRows.java","lineNumber":93,"sourceCode":"\n      //rowSetWhenIdentical is use in case the comparison is IDENTICAL.\n      //this should be the \"Comparison\" stream but can be the \"Reference\" stream for backward compatibility (PDI-736)\n      String useRefWhenIdenticalVar = Const\n        .NVL( System.getProperty( Const.KETTLE_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL ), \"N\" );\n      if ( \"N\".equalsIgnoreCase( useRefWhenIdenticalVar ) ) {\n        //use the reference stream (as per documentation)\n        useRefWhenIdentical = false;\n      } else {\n        //use the comparison stream (for backward compatibility)\n        useRefWhenIdentical = true;\n      }\n      data.one = getRowFrom( data.oneRowSet );\n      data.two = getRowFrom( data.twoRowSet );\n\n      try {\n        checkInputLayoutValid( data.oneRowSet.getRowMeta(), data.twoRowSet.getRowMeta() );\n      } catch ( KettleRowException e ) {\n        throw new KettleException( BaseMessages.getString( PKG, \"MergeRows.Exception.InvalidLayoutDetected\" ), e );\n      }\n\n      if ( data.one != null ) {\n        // Find the key indexes:\n        data.keyNrs = new int[ meta.getKeyFields().length ];\n        for ( int i = 0; i < data.keyNrs.length; i++ ) {\n          data.keyNrs[ i ] = data.oneRowSet.getRowMeta().indexOfValue( meta.getKeyFields()[ i ] );\n          if ( data.keyNrs[ i ] < 0 ) {\n            String message =\n              BaseMessages.getString( PKG, \"MergeRows.Exception.UnableToFindFieldInReferenceStream\", meta\n                .getKeyFields()[ i ] );\n            logError( message );\n            throw new KettleStepException( message );\n          }\n        }\n      }\n\n      if ( data.two != null ) {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/mergerows/MergeRows.java#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"See trigger scenarios.","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."],"exampleFix":"// before: compare stream missing 'updated_date'\nreference: [id, name, updated_date]\ncompare:    [id, name]\n// after: add Select values step on compare branch to include updated_date (Date)\ncompare:    [id, name, updated_date]","handlingStrategy":"validation","validationCode":"// Java: compare the two input layouts before running\nStepMeta mergeRows = transMeta.findStep(\"Merge Rows\");\nRowMetaInterface ref = transMeta.getPrevStepFields(mergeRows, 0);\nRowMetaInterface cmp = transMeta.getPrevStepFields(mergeRows, 1);\nif (!ref.equals(cmp)) {\n  throw new IllegalStateException(\"Merge Rows input layouts differ\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  trans.execute(null);\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"InvalidLayoutDetected\")) {\n    // inspect e.getCause() (KettleRowException) for the exact field mismatch\n  }\n}","preventionTips":["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."],"tags":["kettle","merge-rows","row-metadata","layout-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}