pentaho/pentaho-kettle · error · KettleException

AppendMeta.Exception.UnableToSaveStepInfo

Error message

AppendMeta.Exception.UnableToSaveStepInfo

What it means

AppendMeta.saveRep throws KettleException wrapping 'AppendMeta.Exception.UnableToSaveStepInfo' (with id_step appended) when saving head_name/tail_name step attributes to the repository fails. The message concatenates id_step directly after the localized text. It indicates a repository write failure while persisting the transformation.

Solutions

  1. Check the repository database is reachable and writable.
  2. Ensure the repository user has INSERT/UPDATE permission on r_step_attribute.
  3. Reconnect the repository in Spoon and re-save the transformation.
  4. Verify the Append step's head and tail hops are defined before saving.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check write access before saving
try (Connection c = repoConnection) {
  DatabaseMetaData md = c.getMetaData();
  boolean canWrite = !md.isReadOnly();
  if (!canWrite) throw new IllegalStateException("Repository is read-only");
}

Try / catch

try {
  transMeta.saveRep(rep, metaStore, transName, transObjectId);
} catch (KettleException e) {
  logError("Save failed for step " + e.getMessage(), e);
  // check DB connectivity/permissions, then retry save
}

Prevention

When it happens

Trigger: Calling saveRep (via saving a transformation) when rep.saveStepAttribute throws: DB down, read-only repository user, constraint violation, or missing head/tail stream subjects.

Common situations: Repository database out of space or locked; user lacking INSERT/UPDATE rights on r_step_attribute; saving after disconnecting the repository session.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/00e41cce50d72623. Report an issue: GitHub.

Appendix: source

Thrown at plugins/core/impl/src/main/java/org/pentaho/di/trans/steps/append/AppendMeta.java:128

      StreamInterface headStream = infoStreams.get( 0 );
      StreamInterface tailStream = infoStreams.get( 1 );
      headStream.setSubject( rep.getStepAttributeString( id_step, "head_name" ) );
      tailStream.setSubject( rep.getStepAttributeString( id_step, "tail_name" ) );
    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString(
        PKG, "AppendMeta.Exception.UnexpectedErrorReadingStepInfo" ), e );
    }
  }

  public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_transformation, ObjectId id_step ) throws KettleException {
    try {
      List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();
      StreamInterface headStream = infoStreams.get( 0 );
      StreamInterface tailStream = infoStreams.get( 1 );
      rep.saveStepAttribute( id_transformation, id_step, "head_name", headStream.getStepname() );
      rep.saveStepAttribute( id_transformation, id_step, "tail_name", tailStream.getStepname() );
    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString( PKG, "AppendMeta.Exception.UnableToSaveStepInfo" )
        + id_step, e );
    }
  }

  @Override
  public void searchInfoAndTargetSteps( List<StepMeta> steps ) {
    StepIOMetaInterface ioMeta = getStepIOMeta();
    List<StreamInterface> infoStreams = ioMeta.getInfoStreams();
    for ( StreamInterface stream : infoStreams ) {
      stream.setStepMeta( StepMeta.findStep( steps, (String) stream.getSubject() ) );
    }
  }

  public boolean chosesTargetSteps() {
    return false;
  }

  public String[] getTargetSteps() {

View on GitHub (pinned to f3058517a1)