pentaho/pentaho-kettle · error · KettleXMLException
GroupByMeta.Exception.UnableToLoadStepInfoFromXML
GroupByMeta.Exception.UnableToLoadStepInfoFromXML
Error message
GroupByMeta.Exception.UnableToLoadStepInfoFromXML
What it means
GroupByMeta.loadXML wraps any exception thrown while parsing the step's XML (via readData) in this KettleXMLException. It means the <step> XML fragment for a GroupBy step is malformed or missing expected nodes, so the step metadata could not be reconstructed.
Solutions
- Open the .ktr in Spoon and fix or recreate the GroupBy step's XML section
- Validate the XML contains all expected tags (group, aggregates, directory, prefix, give_back_row)
- Compare against a working GroupBy step definition and restore missing nodes
- Check the wrapped cause 'e' in the log to find the exact failing parse line
- Re-export or regenerate the transformation rather than hand-editing
Example fix
// before (truncated XML) <fields><field><name>grp</name></fields> // after <fields> <field><name>grp</name><aggregate>grp</aggregate><type>GroupConcat</type></field> </fields>
Defensive patterns
Strategy: validation
Validate before calling
// validate the GroupBy XML section before loadXML
Document doc = Xml.load( ktrFile );
Node step = XPath.selectNode( doc, "//step[type='GroupBy']" );
for ( String tag : new String[] { "group", "fields", "directory", "prefix", "give_back_row" } ) {
if ( XPath.selectSingleNode( step, tag ) == null ) {
throw new IllegalArgumentException( "GroupBy step missing <" + tag + "> node" );
}
} Try / catch
try {
transMeta.loadXML( file, null, false, null, null, true );
} catch ( KettleXMLException e ) {
if ( e.getMessage().contains( "UnableToLoadStepInfoFromXML" ) ) {
log.error( "GroupBy step XML invalid: {}", file, e.getCause() );
} else { throw e; }
} Prevention
- Never hand-edit .ktr files; edit in Spoon
- Keep export/import Pentaho versions consistent
- Validate .ktr XML against the schema after external edits
- Back up transformations before bulk edits
When it happens
Trigger: loadXML calls readData on a transformation .ktr; getElementByTag returns bad values or Integer.parseInt/field parsing fails on attributes like group/aggregate fields, directory, prefix, or give_back_row.
Common situations: Hand-edited or truncated .ktr files; transformations exported from a newer/older Pentaho version with different XML schema; copy-paste between transformations losing child nodes; corrupt repository export.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- GroupByMeta.Exception.UnexpectedErrorInReadingStepInfoFromRepository
- SETVARIABLE0004
- ColumnExistsMeta.Exception.UnableToReadStepInfo
- CreditCardValidatorMeta.Exception.UnableToReadStepInfo
- Error loading transformation step from XML
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/5efdd33259dfb4e8.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/groupby/GroupByMeta.java:398
subjectField[ i ] = XMLHandler.getTagValue( fnode, "subject" );
aggregateType[ i ] = getType( XMLHandler.getTagValue( fnode, "type" ) );
if ( aggregateType[ i ] == TYPE_GROUP_COUNT_ALL
|| aggregateType[ i ] == TYPE_GROUP_COUNT_DISTINCT || aggregateType[ i ] == TYPE_GROUP_COUNT_ANY ) {
hasNumberOfValues = true;
}
valueField[ i ] = XMLHandler.getTagValue( fnode, "valuefield" );
}
String giveBackRow = XMLHandler.getTagValue( stepnode, "give_back_row" );
if ( Utils.isEmpty( giveBackRow ) ) {
alwaysGivingBackOneRow = hasNumberOfValues;
} else {
alwaysGivingBackOneRow = "Y".equalsIgnoreCase( giveBackRow );
}
} catch ( Exception e ) {
throw new KettleXMLException( BaseMessages.getString(
PKG, "GroupByMeta.Exception.UnableToLoadStepInfoFromXML" ), e );
}
}
public static final int getType( String desc ) {
for ( int i = 0; i < typeGroupCode.length; i++ ) {
if ( typeGroupCode[ i ].equalsIgnoreCase( desc ) ) {
return i;
}
}
for ( int i = 0; i < typeGroupLongDesc.length; i++ ) {
if ( typeGroupLongDesc[ i ].equalsIgnoreCase( desc ) ) {
return i;
}
}
return 0;
}
View on GitHub (pinned to f3058517a1)