pentaho/pentaho-kettle · error · KettleXMLException

GPBulkLoaderMeta.Exception.UnableToReadStepInfoFromXML

Error message

GPBulkLoaderMeta.Exception.UnableToReadStepInfoFromXML

What it means

GPBulkLoaderMeta.readData() parses the step's XML node to restore saved settings. Any unexpected exception during parsing (missing element dereferenced, wrong data type, malformed XML structure) is wrapped in a KettleXMLException whose message is the localized 'UnableToReadStepInfoFromXML' string. It is a generic deserialization-failure wrapper for this step's metadata.

Solutions

  1. Look at e.getCause() (and its stack trace line in readData) to find which attribute failed to parse.
  2. Open the transformation in Spoon and re-save the GP Bulk Loader step so it regenerates valid XML.
  3. Compare the step's <fields> XML block against a freshly created step and fix/remove the malformed element.
  4. Upgrade or align the gp-bulk-loader plugin version with the one that wrote the transformation file.

Example fix

// before: hand-edited step XML missing <field> sub-elements
<field><name>id</name></field>

// after: complete schema as written by Spoon
<field>
  <column_name>id</column_name>
  <stream_name>id</stream_name>
  <date_mask></date_mask>
</field>
Defensive patterns

Strategy: try-catch

Validate before calling

// validate the step XML before loading it
org.w3c.dom.Node stepNode = /* the <step> node */;
if (!"GPBulkLoader".equals(
      org.pentaho.di.core.xml.XMLHandler.getTagValue(stepNode, "type")))
  throw new IllegalArgumentException("Node is not a GPBulkLoader step");
if (org.pentaho.di.core.xml.XMLHandler.getNodes(stepNode, "fields").isEmpty())
  throw new IllegalArgumentException("GPBulkLoader step XML missing <fields> block");

Try / catch

try {
  transMeta.loadXML(file, null, null, null, null, true, listener);
} catch (KettleXMLException e) {
  if (e.getMessage().contains("UnableToReadStepInfoFromXML")) {
    logError("GPBulkLoader step XML unreadable", e.getCause());
    // re-create the step in Spoon or repair the XML element identified by the cause
  } else throw e;
}

Prevention

When it happens

Trigger: loadXML(node, ...) -> readData(node) encounters malformed or unexpected XML: an expected child element is absent so a lookup returns null and later code dereferences it; attribute values cannot be parsed (e.g. non-numeric where a number is expected); the XML node passed belongs to a different step or an incompatible plugin version.

Common situations: Transformation XML hand-edited and an element removed/renamed; transformation produced by a much older or newer plugin version with a schema change; corrupted repository export; copy-paste of step XML between transformations with incompatible metadata.

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

Appendix: source

Thrown at plugins/gp-bulk-loader/core/src/main/java/org/pentaho/di/trans/steps/gpbulkloader/GPBulkLoaderMeta.java:291

        fieldTable[i] = XMLHandler.getTagValue( vnode, "stream_name" );
        fieldStream[i] = XMLHandler.getTagValue( vnode, "field_name" );
        if ( fieldStream[i] == null ) {
          fieldStream[i] = fieldTable[i]; // default: the same name!
        }
        String locDateMask = XMLHandler.getTagValue( vnode, "date_mask" );
        if ( locDateMask == null ) {
          dateMask[i] = "";
        } else {
          if ( GPBulkLoaderMeta.DATE_MASK_DATE.equals( locDateMask )
            || GPBulkLoaderMeta.DATE_MASK_DATETIME.equals( locDateMask ) ) {
            dateMask[i] = locDateMask;
          } else {
            dateMask[i] = "";
          }
        }
      }
    } catch ( Exception e ) {
      throw new KettleXMLException( BaseMessages.getString(
        PKG, "GPBulkLoaderMeta.Exception.UnableToReadStepInfoFromXML" ), e );
    }
  }

  @Override
  public void setDefault() {
    fieldTable = null;
    databaseMeta = null;
    maxErrors = 50;
    schemaName = "";
    tableName = BaseMessages.getString( PKG, "GPBulkLoaderMeta.DefaultTableName" );
    loadMethod = METHOD_AUTO_END;
    loadAction = ACTION_APPEND;
    PsqlPath = "PsqlPath";
    controlFile = "control${Internal.Step.CopyNr}.cfg";
    dataFile = "load${Internal.Step.CopyNr}.dat";
    logFile = "";
    encoding = "";

View on GitHub (pinned to f3058517a1)