pentaho/pentaho-kettle · error · KettleXMLException

AppendMeta.Exception.UnableToLoadStepInfo

Error message

AppendMeta.Exception.UnableToLoadStepInfo

What it means

AppendMeta.readData throws KettleXMLException wrapping message 'AppendMeta.Exception.UnableToLoadStepInfo' when parsing the step's XML node fails. It reads head_name and tail_name tags via XMLHandler; any exception during that DOM access (malformed XML, missing stepnode) is wrapped. It signals the transformation .ktr could not be deserialized for this Append step.

Solutions

  1. Open the .ktr in Spoon and re-save the Append step so the head_name/tail_name XML tags are regenerated correctly.
  2. Validate the XML file is well-formed (xmllint) and not truncated.
  3. Check that head/tail hop steps referenced by the Append step still exist and are connected.
  4. Align Pentaho Kettle versions between the environment that saved the file and the one loading it.

Example fix

// before: hand-edited XML missing tags
<step name="Append"><type>Append</type></step>
// after: regenerated by Spoon with both hop names
<step name="Append"><head_name>Step A</head_name><tail_name>Step B</tail_name></step>
Defensive patterns

Strategy: try-catch

Validate before calling

// Before loading: check XML is well-formed and has the tags
Document doc = XMLHandler.loadXMLFile(ktrFile);
if (XMLHandler.getTagValue(doc, "step", "head_name") == null
    || XMLHandler.getTagValue(doc, "step", "tail_name") == null) {
  throw new IllegalArgumentException("Append step XML missing head_name/tail_name");
}

Try / catch

try {
  transMeta.loadXML(file, null, null, null, null, true, monitor);
} catch (KettleXMLException e) {
  if (e.getMessage().contains("UnableToLoadStepInfo") || e.getCause() != null) {
    logError("Corrupt Append step XML: " + e.getMessage(), e);
    // fall back to re-exporting the transformation from a good source
  }
}

Prevention

When it happens

Trigger: Loading a .ktr file whose <step type='Append'> node is malformed or whose XML is otherwise unreadable, via loadXML -> readData; XMLHandler.getTagValue throwing or getStepIOMeta().getInfoStreams() lacking entries.

Common situations: Hand-edited or truncated .ktr files; transformations saved by a newer/older Pentaho version with a changed XML schema; corrupted repository export imported from XML.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

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

  public String getXML() {
    StringBuilder retval = new StringBuilder();

    List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();
    retval.append( XMLHandler.addTagValue( "head_name", infoStreams.get( 0 ).getStepname() ) );
    retval.append( XMLHandler.addTagValue( "tail_name", infoStreams.get( 1 ).getStepname() ) );

    return retval.toString();
  }

  private void readData( Node stepnode ) throws KettleXMLException {
    try {
      List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();
      StreamInterface headStream = infoStreams.get( 0 );
      StreamInterface tailStream = infoStreams.get( 1 );
      headStream.setSubject( XMLHandler.getTagValue( stepnode, "head_name" ) );
      tailStream.setSubject( XMLHandler.getTagValue( stepnode, "tail_name" ) );
    } catch ( Exception e ) {
      throw new KettleXMLException( BaseMessages.getString( PKG, "AppendMeta.Exception.UnableToLoadStepInfo" ), e );
    }
  }

  public void setDefault() {
  }

  public void readRep( Repository rep, IMetaStore metaStore, ObjectId id_step, List<DatabaseMeta> databases ) throws KettleException {
    try {
      List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();
      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 );
    }
  }

View on GitHub (pinned to f3058517a1)