pentaho/pentaho-kettle · error · KettleXMLException
Unable to format Node as XML
Error message
Unable to format Node as XML
What it means
Node2String serializes a DOM Node back to an XML string using a Transformer from XMLParserFactoryProducer.createSecureTransformerFactory(). Any TransformerConfigurationException or transformation failure (TransformerException wrapped as Exception) is rethrown as KettleXMLException("Unable to format Node as XML").
Solutions
- Check e.getCause(): TransformerConfigurationException points to factory problems; fix the -Djavax.xml.transform.TransformerFactory system property or remove conflicting Xalan jars.
- Ensure the Node was created by a document builder compatible with the transformer (same DOM implementation).
- Update to a consistent parser/transformer stack (bundled JAXP versions).
- If only debugging, log the node with a simpler serializer or rebuild the node via XMLHandler.loadXMLString/XMLHandler.createDocumentBuilder.
Example fix
// before
String xml = XMLHandler.Node2String(node); // fails with custom TransformerFactory
// after
String xml;
try {
xml = XMLHandler.Node2String(node);
} catch (KettleXMLException e) {
log.warn("Node2String failed: " + e.getCause());
xml = node.toString(); // or fix factory config
} Defensive patterns
Strategy: try-catch
Validate before calling
if (node == null || node.getNodeType() != Node.ELEMENT_NODE && node.getNodeType() != Node.DOCUMENT_NODE) {
throw new KettleException("Not a serializable node");
} Type guard
boolean isSerializableNode(Node n) {
return n != null && (n.getNodeType() == Node.ELEMENT_NODE
|| n.getNodeType() == Node.DOCUMENT_NODE);
} Try / catch
try {
xml = XMLHandler.Node2String(node);
} catch (KettleXMLException e) {
log.error("Serialize failed: " + e.getCause()); // TransformerException
} Prevention
- Remove conflicting Xalan/Xerces jars so the secure factory loads
- Build nodes with the same DOM implementation you serialize
- Pin javax.xml.transform.TransformerFactory system property explicitly
When it happens
Trigger: XMLHandler.Node2String(Node) where newTransformer() fails (secure factory/transformer feature misconfiguration) or t.transform() fails (DOM contains nodes the transformer cannot serialize, or the node tree is inconsistent).
Common situations: Custom Xalan/Xerces versions on the classpath conflicting with the secure factory, JVM system properties forcing an incompatible TransformerFactory, nodes built by a different DOM implementation (namespace-incompatible trees).
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
- AddSequenceMeta.Exception.ErrorLoadingStepInfo
- AnalyticQueryMeta.Exception.UnableToLoadStepInfoFromXML
- ChangeFileEncodingMeta.Exception.UnableToReadStepInfo
- CombinationLookupMeta.Exception.UnableToLoadStepInfo
- Error loading transformation step from XML
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/a302e0d996bd35c6.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/xml/XMLHandler.java:1283
}
public static String closeTag( String tag ) {
return closeTag( new StringBuilder(), tag ).toString();
}
public static StringBuilder closeTag( StringBuilder builder, String tag ) {
return builder.append( "</" ).append( tag ).append( '>' );
}
public static String formatNode( Node node ) throws KettleXMLException {
StringWriter sw = new StringWriter();
try {
Transformer t = XMLParserFactoryProducer.createSecureTransformerFactory().newTransformer();
t.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
t.transform( new DOMSource( node ), new StreamResult( sw ) );
} catch ( Exception e ) {
throw new KettleXMLException( "Unable to format Node as XML", e );
}
return sw.toString();
}
/**
* <p>Checks if a given {@link FileObject} instance corresponds to an existing file.</p>
*
* @param fileObject the {@link FileObject} instance to check
* @return <code>true</code> if the file exists, <code>false</code> otherwise
* @throws KettleXMLException if an error occurred while checking
*/
public static boolean checkFile( FileObject fileObject ) throws KettleXMLException {
try {
return fileObject != null && fileObject.exists() && fileObject.isFile();
} catch ( FileSystemException e ) {
throw new KettleXMLException( BaseMessages.getString(
PKG, "XMLHandler.errorCheckingFileExistence", fileObject.toString() ), e );
}View on GitHub (pinned to f3058517a1)