pentaho/pentaho-kettle · error · KettleXMLException

Unable to load step info from XML

Error message

Unable to load step info from XML

What it means

JsonOutputMeta.readData parses the step's XML definition (<fields> nodes, encoding, output value, etc.) with XMLHandler; any exception during parsing is rethrown as a KettleXMLException 'Unable to load step info from XML'. This happens when a transformation (.ktr) file's JSON Output step XML is malformed or incompatible.

Solutions

  1. Open the .ktr in a text editor and inspect the <step type="JsonOutput"> block for malformed or missing XML tags.
  2. Restore the transformation from version control or repository history.
  3. Recreate the JSON Output step in Spoon and re-configure its fields.
  4. Upgrade/align the PDI and JSON plugin versions so the XML schema matches.

Example fix

// before (corrupt ktr XML)
<field><name>foo<element>foo</field>
// after
<field><name>foo</name><element>foo</element></field>
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the ktr XML before loading
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
Document doc = f.newDocumentBuilder().parse(new File("trans.ktr"));
NodeList steps = doc.getElementsByTagName("step");
for (int i = 0; i < steps.getLength(); i++) {
  if ("JsonOutput".equals(steps.item(i).getAttributes().getNamedItem("type").getNodeValue())) {
    if (((Element) steps.item(i)).getElementsByTagName("fields").getLength() == 0)
      throw new IllegalStateException("JsonOutput step missing <fields> block");
  }
}

Try / catch

try { transMeta = new TransMeta("trans.ktr"); } catch (KettleXMLException e) {
  if (e.getMessage().contains("Unable to load step info from XML")) {
    log.error("Corrupt/incompatible .ktr; restore from VCS or recreate the step", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: loadXML calls readData on a Node whose expected tags are missing/corrupt, or XMLHandler throws while reading them (bad XML structure, incompatible plugin version producing unexpected layout).

Common situations: Hand-edited or corrupted .ktr file; opening a transformation created by a newer/older PDI version; partial file from a failed save or bad merge; repository object XML truncated.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at plugins/json/core/src/main/java/org/pentaho/di/trans/steps/jsonoutput/JsonOutputMeta.java:298

      dateInFilename = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "add_date" ) );
      timeInFilename = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "add_time" ) );
      DoNotOpenNewFileInit = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "DoNotOpenNewFileInit" ) );
      servletOutput = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "servlet_output" ) );

      Node fields = XMLHandler.getSubNode( stepnode, "fields" );
      int nrfields = XMLHandler.countNodes( fields, "field" );

      allocate( nrfields );

      for ( int i = 0; i < nrfields; i++ ) {
        Node fnode = XMLHandler.getSubNodeByNr( fields, "field", i );

        outputFields[i] = new JsonOutputField();
        outputFields[i].setFieldName( XMLHandler.getTagValue( fnode, "name" ) );
        outputFields[i].setElementName( XMLHandler.getTagValue( fnode, "element" ) );
      }
    } catch ( Exception e ) {
      throw new KettleXMLException( "Unable to load step info from XML", e );
    }
  }

  public void setDefault() {
    encoding = Const.XML_ENCODING;
    outputValue = "outputValue";
    jsonBloc = "data";
    nrRowsInBloc = "1";
    operationType = OPERATION_TYPE_WRITE_TO_FILE;
    extension = "js";
    int nrfields = 0;

    allocate( nrfields );

    for ( int i = 0; i < nrfields; i++ ) {
      outputFields[i] = new JsonOutputField();
      outputFields[i].setFieldName( "field" + i );
      outputFields[i].setElementName( "field" + i );

View on GitHub (pinned to f3058517a1)