{"record":{"id":"289e8b2ab92e266d","repo":"pentaho/pentaho-kettle","slug":"mergerowsmeta-exception-unabletosavestepinfo","errorCode":"MergeRowsMeta.Exception.UnableToSaveStepInfo","errorMessage":"MergeRowsMeta.Exception.UnableToSaveStepInfo","messagePattern":"MergeRowsMeta\\.Exception\\.UnableToSaveStepInfo","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/mergerows/MergeRowsMeta.java","lineNumber":266,"sourceCode":"    try {\n      for ( int i = 0; i < keyFields.length; i++ ) {\n        rep.saveStepAttribute( id_transformation, id_step, i, \"key_field\", keyFields[i] );\n      }\n\n      for ( int i = 0; i < valueFields.length; i++ ) {\n        rep.saveStepAttribute( id_transformation, id_step, i, \"value_field\", valueFields[i] );\n      }\n\n      rep.saveStepAttribute( id_transformation, id_step, \"flag_field\", flagField );\n\n      List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();\n      StreamInterface referenceStream = infoStreams.get( 0 );\n      StreamInterface compareStream = infoStreams.get( 1 );\n\n      rep.saveStepAttribute( id_transformation, id_step, \"reference\", referenceStream.getStepname() );\n      rep.saveStepAttribute( id_transformation, id_step, \"compare\", compareStream.getStepname() );\n    } catch ( Exception e ) {\n      throw new KettleException( BaseMessages.getString( PKG, \"MergeRowsMeta.Exception.UnableToSaveStepInfo\" )\n        + id_step, e );\n    }\n  }\n\n  public boolean chosesTargetSteps() {\n    return false;\n  }\n\n  public String[] getTargetSteps() {\n    return null;\n  }\n\n  @Override\n  public void getFields( Bowl bowl, RowMetaInterface r, String name, RowMetaInterface[] info, StepMeta nextStep,\n    VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException {\n    // We don't have any input fields here in \"r\" as they are all info fields.\n    // So we just merge in the info fields.\n    //","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/mergerows/MergeRowsMeta.java#L248-L284","documentation":"MergeRowsMeta.saveRep() persists the Merge Rows step's configuration (reference and compare stream step names) to the Kettle repository. If any exception occurs while saving those step attributes — typically a repository connectivity or persistence failure — it is wrapped in a KettleException with the 'UnableToSaveStepInfo' message plus the step ID.","triggerScenarios":"Calling TransMeta.saveRep()/repository save of a transformation containing a Merge Rows step when infoStreams lack expected entries, or the repository write of the 'reference'/'compare' attributes fails (repo down, bad connection, read-only repo).","commonSituations":"Repository database temporarily unreachable during save; saving a transformation whose Merge Rows step hops were not yet wired so stream info is incomplete; running with a read-only or partially migrated repository.","solutions":["Verify the Kettle repository connection is up and writable before saving the transformation","Open the transformation in Spoon, ensure the Merge Rows step has both reference and compare hops connected, then re-save","Check repository DB logs/permissions (read-only user, quota) and fix, then retry the save","Upgrade/patch Kettle if repository schema version mismatches the engine version"],"exampleFix":"// before\nrep.saveStepAttribute( id_transformation, id_step, \"reference\", referenceStream.getStepname() );\n// after\n// ensure streams are connected first\nif ( infoStreams.size() < 2 || infoStreams.get(0).getStepMeta() == null || infoStreams.get(1).getStepMeta() == null ) {\n  throw new KettleException( \"Merge Rows step must have reference and compare input hops before saving\" );\n}\nrep.saveStepAttribute( id_transformation, id_step, \"reference\", referenceStream.getStepname() );","handlingStrategy":"try-catch","validationCode":"// before saving\nif ( transMeta.findStep( \"Merge Rows\" ) != null ) {\n  MergeRowsMeta m = (MergeRowsMeta) transMeta.findStep( \"Merge Rows\" ).getStepMetaInterface();\n  if ( m.getInfoStreams().size() < 2 || m.getInfoStreams().get(0).getStepMeta() == null || m.getInfoStreams().get(1).getStepMeta() == null ) {\n    throw new IllegalStateException( \"Merge Rows step missing reference/compare input hops\" );\n  }\n}\nif ( !repository.isConnected() ) throw new IllegalStateException( \"Repository not connected\" );","typeGuard":"function hasConnectedStreams( mergeRowsMeta ) {\n  const s = mergeRowsMeta.getInfoStreams();\n  return s != null && s.length >= 2 && s[0].getStepMeta() != null && s[1].getStepMeta() != null;\n}","tryCatchPattern":"try {\n  transMeta.saveRep( repository, monitor );\n} catch ( KettleException e ) {\n  if ( e.getMessage() != null && e.getMessage().contains( \"UnableToSaveStepInfo\" ) ) {\n    // check repository connectivity/permissions, then retry or re-save via Spoon\n  } else { throw e; }\n}","preventionTips":["Confirm repository connectivity before batch saves","Always wire reference and compare hops before saving a Merge Rows step","Use a repository user with write privileges","Wrap programmatic saves with retry on transient DB failures"],"tags":["kettle","repository","persistence","merge-rows"],"backgroundTag":"database-write-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"}