pentaho/pentaho-kettle · error · KettleXMLException

Unable to load step info from XML

Error message

Unable to load step info from XML

What it means

AvroOutputMetaBase.readData wraps any exception raised while parsing the step's XML node into a KettleXMLException with message 'Unable to load step info from XML'. This runs when a transformation (.ktr) containing the Avro Output step is loaded, reading tags such as schemaFilename, namespace, docValue, recordName via XMLHandler. The original exception is chained as the cause.

Solutions

  1. Read the chained cause (e.getCause()) to pinpoint which tag/value failed to parse.
  2. Open the .ktr in a text editor and verify the <step> node for the Avro Output contains well-formed children (schemaFilename, namespace, docValue, recordName).
  3. Re-save the transformation from the PDI version that matches the installed Avro plugin, or align plugin versions.
  4. Restore the .ktr from backup/VC if it was truncated or hand-edited incorrectly.
  5. Delete and re-create the Avro Output step if its node is irreparably malformed.

Example fix

<!-- before (hand-edited ktr, broken tag) -->
<schemaFilename>/data/sch.avsc</schemaFilenam>
<!-- after -->
<schemaFilename>/data/sch.avsc</schemaFilename>
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the .ktr before load
Document doc;
try {
  doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ktrPath));
} catch (Exception e) { throw new IOException("Malformed ktr XML: " + ktrPath, e); }
NodeList steps = doc.getElementsByTagName("step");
for (int i = 0; i < steps.getLength(); i++) {
  Element el = (Element) steps.item(i);
  if (el.getElementsByTagName("schemaFilename").getLength() == 0)
    throw new IOException("Avro Output step missing schemaFilename tag");
}

Try / catch

try {
  transMeta.loadXML(ktrFile, null, false, null, null, true);
} catch (KettleXMLException e) {
  logError("Failed to load step XML: " + e.getCause(), e);
  // fall back to backup copy or re-save from matching PDI/plugin version
}

Prevention

When it happens

Trigger: loadXML -> readData encounters malformed or missing XML structure for the step node — e.g. a .ktr edited by hand or produced by an incompatible PDI version, a truncated file, or unexpected tag content that makes XMLHandler.getTagValue or surrounding parsing code throw.

Common situations: Opening a transformation saved by a newer/older PDI or plugin version whose Avro Output XML layout changed; hand-editing a .ktr and breaking the step node; file transfer corruption; missing plugin jar so the XML cannot be interpreted as expected.

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/b4b9cfb335425483. Report an issue: GitHub.

Appendix: source

Thrown at plugins/avro-format/core/src/main/java/org/pentaho/di/trans/steps/avro/output/AvroOutputMetaBase.java:181

        outputField.setPrecision( XMLHandler.getTagValue( fnode, PRECISION ) );
        outputField.setScale( XMLHandler.getTagValue( fnode, SCALE ) );
        outputField.setAllowNull( XMLHandler.getTagValue( fnode, NULLABLE ) );
        outputField.setDefaultValue( XMLHandler.getTagValue( fnode, DEFAULT )  );
        avroOutputFields.add( outputField );
      }
      this.outputFields = avroOutputFields;

      compressionType = XMLHandler.getTagValue( stepnode, FieldNames.COMPRESSION );
      dateTimeFormat = XMLHandler.getTagValue( stepnode, FieldNames.DATE_FORMAT );
      dateInFileName = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, FieldNames.DATE_IN_FILE_NAME ) );
      timeInFileName = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, FieldNames.TIME_IN_FILE_NAME ) );
      schemaFilename = XMLHandler.getTagValue( stepnode, FieldNames.SCHEMA_FILENAME );
      namespace = XMLHandler.getTagValue( stepnode, FieldNames.NAMESPACE );
      docValue = XMLHandler.getTagValue( stepnode, FieldNames.DOC_VALUE );
      recordName = XMLHandler.getTagValue( stepnode, FieldNames.RECORD_NAME );

    } catch ( Exception e ) {
      throw new KettleXMLException( "Unable to load step info from XML", e );
    }
  }

  @Override
  public String getXML() {
    StringBuilder retval = new StringBuilder( 800 );
    final String INDENT = "    ";

    retval.append( INDENT ).append( XMLHandler.addTagValue( FILE_NAME, filename ) );
    parentStepMeta.getParentTransMeta().getNamedClusterEmbedManager().registerUrl( filename );
    retval.append( INDENT ).append( XMLHandler.addTagValue( FieldNames.OVERRIDE_OUTPUT, overrideOutput ) );

    retval.append( "    <fields>" ).append( Const.CR );
    for ( int i = 0; i < outputFields.size(); i++ ) {
      AvroOutputField field = outputFields.get( i );

      if ( field.getPentahoFieldName() != null && field.getPentahoFieldName().length() != 0 ) {
        retval.append( "      <field>" ).append( Const.CR );

View on GitHub (pinned to f3058517a1)