pentaho/pentaho-kettle · error · KettleXMLException
MemoryGroupByMeta.Exception.UnableToLoadStepInfoFromXML
MemoryGroupByMeta.Exception.UnableToLoadStepInfoFromXML
Error message
MemoryGroupByMeta.Exception.UnableToLoadStepInfoFromXML
What it means
MemoryGroupByMeta.readData() (invoked via loadXML) parses the MemoryGroupBy step's definition from a transformation XML node — grouping fields, aggregation fields/types, and the give_back_row flag. Any exception during this parsing is wrapped in a KettleXMLException with this message key, meaning the step could not be reconstructed from the XML. The original parse/conversion error is chained as the cause.
Solutions
- Inspect the chained cause to find the exact XML parsing failure (element name, line, value).
- Open the .ktr in a text editor and validate the MemoryGroupBy step's XML block; fix or remove malformed attributes/elements.
- Re-create the MemoryGroupBy step in Spoon and re-save the transformation to regenerate clean XML.
- Check the version of Pentaho used to create the file versus the runtime version; migrate the transformation if schemas differ.
Example fix
// before: ambiguous int parse on possibly-missing node int nrValues = Integer.parseInt(XMLHandler.getTagValue(stepnode, "number_of_values")); // after: default when absent String nrStr = XMLHandler.getTagValue(stepnode, "number_of_values"); int nrValues = Utils.isEmpty(nrStr) ? 0 : Integer.parseInt(nrStr);
Defensive patterns
Strategy: try-catch
Validate before calling
// validate XML before loadXML
String xml = new String(Files.readAllBytes(Paths.get(ktrPath)), StandardCharsets.UTF_8);
Document doc = XMLHandler.loadXMLString(xml); // throws early on malformed XML
Node memGroup = XMLHandler.getSubNode(doc.getDocumentElement(), "step");
if (memGroup == null) throw new IllegalArgumentException("No step node for MemoryGroupBy in XML"); Type guard
boolean isParseableStepNode(Node stepnode) {
return stepnode != null && XMLHandler.getSubNode(stepnode, "fields") != null;
} Try / catch
try {
meta.loadXML(stepnode, databases, metaStore);
} catch (KettleXMLException e) {
logError("MemoryGroupBy XML load failed: " + e.getCause(), e);
throw e;
} Prevention
- Do not hand-edit .ktr files; regenerate them via Spoon.
- Resolve merge conflicts by re-exporting the transformation rather than merging XML by hand.
- Verify XML with a parser/linter before loading programmatically.
- Keep creator and consumer Pentaho versions compatible.
When it happens
Trigger: Loading a .ktr whose <step> node for MemoryGroupBy contains malformed or unexpected XML — missing required child elements, non-numeric values where ints are expected (e.g. number_of_values), or a structurally corrupt XML file.
Common situations: Hand-edited or truncated .ktr files; transformations produced by newer/older Pentaho versions with changed XML schema; version-control merge conflicts inside the XML; XML with wrong encoding that breaks parsing.
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
- AggregateRowsMeta.Exception.UnableToLoadStepInfo
- CubeOutputMeta.Exception.UnableToLoadStepInfo
- DatabaseJoinMeta.Exception.UnableToLoadStepInfo
- DelayMeta.Exception.UnableToReadStepInfo
- DetectLastRowMeta.Exception.UnableToReadStepInfo
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/0d0c5e54719c1646.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/memgroupby/MemoryGroupByMeta.java:286
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, "MemoryGroupByMeta.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)