pentaho/pentaho-kettle · error · KettleXMLException

Unable to load step info from XML

Error message

Unable to load step info from XML

What it means

TableInputMeta.readData(), invoked from loadXML(), parses the step's XML node (connection, SQL, 'execute each input row', lazy conversion, cached row meta tags) via XMLHandler. Any exception during parsing is rethrown as a KettleXMLException with the message 'Unable to load step info from XML'.

Solutions

  1. Open the .ktr file in an XML editor and validate it; fix or remove the malformed TableInput step node.
  2. Check the cause chain (KettleXMLException wraps the original exception) to find which tag failed.
  3. Remove or repair the cached row meta node (xml_meta tag) — it is recomputed at runtime.
  4. Recreate the TableInput step in Spoon and re-enter its settings, then re-save the transformation.
  5. Ensure the transformation file was fully written/exported (not truncated) and matches your Pentaho version.

Example fix

// before: missing <row-meta> element breaks new RowMeta(XMLHandler.getSubNode(...)) if code expects it
<step name="Table input" type="TableInput">
  <sql>SELECT ...</sql>
</step>
// after: re-save the step via Spoon so all tags are serialized
<step name="Table input" type="TableInput">
  <sql>SELECT ...</sql>
  <variables_active>Y</variables_active>
  <lazy_conversion_active>N</lazy_conversion_active>
  <cached_row_meta_active>N</cached_row_meta_active>
</step>
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the .ktr XML parses and contains the TableInput node before loading
Document doc = XMLHandler.loadXMLFile(new File("trans.ktr"));
if (doc == null || XMLHandler.getSubNode(doc.getDocumentElement(), "step") == null) {
  throw new IllegalStateException("Transformation XML is malformed");
}

Try / catch

try {
  meta.loadXML(stepnode, databases, metaStore);
} catch (KettleXMLException e) {
  log.error("Step XML invalid: " + KettleUtil.getMessage(e));
  throw e; // or recreate the step from defaults: meta.setDefault();
}

Prevention

When it happens

Trigger: loadXML() is called with a stepnode whose expected tags are malformed or whose cached row-meta subnode (RowMeta.XML_META_TAG) is missing/corrupt, causing XMLHandler.getSubNode/new RowMeta to throw; also a null or non-element stepnode.

Common situations: Hand-edited or truncated .ktr files; transformations exported by other tools or older/newer Pentaho versions missing tags like <row-meta>; copy-pasting step XML fragments between transformations; corrupted repository/export files.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/tableinput/TableInputMeta.java:188

  private void readData( Node stepnode, List<DatabaseMeta> databases ) throws KettleXMLException {
    this.databases = databases;
    try {
      databaseMeta = DatabaseMeta.findDatabase( databases, XMLHandler.getTagValue( stepnode, "connection" ) );
      sql = XMLHandler.getTagValue( stepnode, "sql" );
      rowLimit = XMLHandler.getTagValue( stepnode, "limit" );

      String lookupFromStepname = XMLHandler.getTagValue( stepnode, "lookup" );
      StreamInterface infoStream = getStepIOMeta().getInfoStreams().get( 0 );
      infoStream.setSubject( lookupFromStepname );

      executeEachInputRow = "Y".equals( XMLHandler.getTagValue( stepnode, "execute_each_row" ) );
      variableReplacementActive = "Y".equals( XMLHandler.getTagValue( stepnode, "variables_active" ) );
      lazyConversionActive = "Y".equals( XMLHandler.getTagValue( stepnode, "lazy_conversion_active" ) );
      cachedRowMetaActive = "Y".equals( XMLHandler.getTagValue( stepnode, "cached_row_meta_active" ) );
      cachedRowMeta = new RowMeta( XMLHandler.getSubNode( stepnode, RowMeta.XML_META_TAG ) );

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

  public void setDefault() {
    databaseMeta = null;
    sql = "SELECT <values> FROM <table name> WHERE <conditions>";
    rowLimit = "0";
  }

  protected Database getDatabase() {
    // Added for test purposes
    return new Database( loggingObject, databaseMeta );
  }

  @Override
  public void getFields( Bowl bowl, RowMetaInterface row, String origin, RowMetaInterface[] info, StepMeta nextStep,
    VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException {
    if ( databaseMeta == null ) {

View on GitHub (pinned to f3058517a1)