{"record":{"id":"0a1bb3a2f57f6f14","repo":"pentaho/pentaho-kettle","slug":"multimergejoin-exception-unabletofindspecifiedstep","errorCode":"MultiMergeJoin.Exception.UnableToFindSpecifiedStep","errorMessage":"MultiMergeJoin.Exception.UnableToFindSpecifiedStep","messagePattern":"MultiMergeJoin\\.Exception\\.UnableToFindSpecifiedStep","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/multimerge/MultiMergeJoin.java","lineNumber":145,"sourceCode":"\n    RowMetaInterface rowMeta;\n    data.outputRowMeta = new RowMeta();\n    for ( int i = 0, j = 0; i < inputStepNames.length; i++ ) {\n      inputStepName = inputStepNames[i];\n      if ( !inputStepNameList.contains( inputStepName ) ) {\n        //ignore step with disabled hop.\n        continue;\n      }\n\n      queueEntry = new MultiMergeJoinData.QueueEntry();\n      queueEntry.index = j;\n      data.queueEntries[j] = queueEntry;\n\n      data.results.add( new ArrayList<Object[]>() );\n\n      rowSet = findInputRowSet( inputStepName );\n      if ( rowSet == null ) {\n        throw new KettleException( BaseMessages.getString(\n          PKG, \"MultiMergeJoin.Exception.UnableToFindSpecifiedStep\", inputStepName ) );\n      }\n      data.rowSets[j] = rowSet;\n\n      row = getRowFrom( rowSet );\n      data.rows[j] = row;\n      if ( row == null ) {\n        rowMeta = getTransMeta().getStepFields( inputStepName );\n        data.metas[j] = rowMeta;\n      } else {\n        queueEntry.row = row;\n        rowMeta = rowSet.getRowMeta();\n\n        keyField = meta.getKeyFields()[i];\n        String[] keyFieldParts = keyField.split( \",\" );\n        String keyFieldPart;\n        data.keyNrs[j] = new int[keyFieldParts.length];\n        for ( int k = 0; k < keyFieldParts.length; k++ ) {","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/multimerge/MultiMergeJoin.java#L127-L163","documentation":"processFirstRow() obtains the RowSet for each configured join input via findInputRowSet(inputStepName). If the runtime returns null — no row set is registered for that step name — a KettleException 'UnableToFindSpecifiedStep' is thrown before any rows can be read.","triggerScenarios":"Executing a transformation where the input step passed hop/metadata checks but its RowSet was never created at runtime, e.g. the input step is not actually running, its hop is disabled but skipped the earlier enabled-hop check path, or the step name in the join config doesn't match the live step instance name.","commonSituations":"Join configured to read from a step that executes conditionally or never starts; duplicated transformation where step instance names diverged; cluster/split execution where an input partition is absent; race where input step failed to initialize so its row set is gone.","solutions":["Check the execution log for the input steps' initialization/startup — fix whatever prevents them from starting before the join","Verify each join input hop is enabled and the referenced step names exactly match the live steps in the transformation","Rebuild the transformation's join configuration in Spoon (remove and re-add the input streams) to clear stale step names","Re-run the transformation after confirming all input steps complete their init() successfully"],"exampleFix":"// before\nString inputStepName = streams[i].getStepname(); // \"copy of Table input\" mismatch\nrowSet = findInputRowSet( inputStepName ); // null\n// after\n// ensure config uses the actual step name present in the transformation\nString inputStepName = streams[i].getStepMeta().getName();\nrowSet = findInputRowSet( inputStepName );","handlingStrategy":"try-catch","validationCode":"// before execution, confirm every join input is reachable and will be running\nfor ( StreamInterface s : joinMeta.getInfoStreams() ) {\n  StepMeta sm = s.getStepMeta();\n  if ( sm == null || !sm.isRunning() && transMeta.findTransHop( sm, joinStep, true ) == null ) {\n    throw new IllegalStateException( \"Join input step unavailable at runtime: \" + s.getStepname() );\n  }\n}","typeGuard":"function rowSetExists( joinData, index ) {\n  return joinData.rowSets != null && index < joinData.rowSets.length && joinData.rowSets[index] != null;\n}","tryCatchPattern":"try {\n  trans.start();\n  trans.waitUntilFinished();\n} catch ( KettleException e ) {\n  if ( e.getMessage() != null && e.getMessage().contains( \"UnableToFindSpecifiedStep\" ) ) {\n    // inspect log: input step likely failed init or step name mismatch\n  } else { throw e; }\n}","preventionTips":["Ensure all join input steps initialize successfully — check earlier log errors","Verify step names in the join config exactly match the live transformation steps","Avoid conditional/optional paths that can leave join inputs unstarted","Rebuild join configuration after cloning transformations across environments"],"tags":["kettle","multi-merge-join","rowset","runtime"],"backgroundTag":"resource-not-found","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"}