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

  1. Check e.getCause(): TransformerConfigurationException points to factory problems; fix the -Djavax.xml.transform.TransformerFactory system property or remove conflicting Xalan jars.
  2. Ensure the Node was created by a document builder compatible with the transformer (same DOM implementation).
  3. Update to a consistent parser/transformer stack (bundled JAXP versions).
  4. 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

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


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)