pentaho/pentaho-kettle · error · KettleException

Class [ + repositoryElement.getClass().getName() + ] needs…

Error message

Class [ + repositoryElement.getClass().getName() + ] needs to implement the XML Interface in order to save it to disk

What it means

KettleFileRepository.save() requires that any element written to the file repository either implements XMLInterface or SharedObjectInterface, because the file repository serializes elements to XML files on disk. If a repository element class implements neither, it cannot be persisted and a KettleException naming the offending class is thrown.

Solutions

  1. Make the element class implement XMLInterface (getXML(), loadXML()) so it can be serialized to disk.
  2. Alternatively implement SharedObjectInterface if the element is a shared object suitable for XML storage.
  3. Store non-XML-serializable objects in the metastore instead of the file repository.
  4. Check the named class in the message — it tells you exactly which custom type lacks the interface.

Example fix

// before
public class MyElement implements RepositoryElementInterface { ... }

// after
public class MyElement implements RepositoryElementInterface, XMLInterface {
  public String getXML() { return xml; }
  public void loadXML(Node node, ...) { ... }
}
Defensive patterns

Strategy: type-guard

Validate before calling

boolean savable = element instanceof XMLInterface || element instanceof SharedObjectInterface;

Type guard

boolean canSaveToFileRepo(RepositoryElementInterface e) {
  return e instanceof XMLInterface || e instanceof SharedObjectInterface;
}

Try / catch

try {
  repo.save(element, null, null);
} catch (KettleException e) {
  if (e.getMessage().contains("needs to implement the XML Interface")) {
    log.error("Custom element cannot go to file repo: " + element.getClass().getName());
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling save(element, versionComment, monitor, parentId, used) with a custom or new RepositoryElementInterface implementation that doesn't implement XMLInterface (e.g. a custom plugin object added to a file repository).

Common situations: Custom PDI plugins storing their metadata objects into a file repository; newly introduced core element types used with an older file-repository code path; third-party extensions calling save() generically on arbitrary element types.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/119ebb9f5222f279. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/repository/filerep/KettleFileRepository.java:304

  @Override
  public void save( RepositoryElementInterface repositoryElement, String versionComment,
    ProgressMonitorListener monitor, boolean overwrite ) throws KettleException {
    // We always overwrite so no further changes necessary
    save( repositoryElement, versionComment, monitor, null, overwrite );
  }

  @Override
  public void save( RepositoryElementInterface repositoryElement, String versionComment, Calendar versionDate,
    ProgressMonitorListener monitor, boolean overwrite ) throws KettleException {
    save( repositoryElement, versionComment, monitor, null, overwrite );
  }

  public void save( RepositoryElementInterface repositoryElement, String versionComment,
    ProgressMonitorListener monitor, ObjectId parentId, boolean used ) throws KettleException {
    try {
      if ( !( repositoryElement instanceof XMLInterface )
        && !( repositoryElement instanceof SharedObjectInterface ) ) {
        throw new KettleException( "Class ["
          + repositoryElement.getClass().getName()
          + "] needs to implement the XML Interface in order to save it to disk" );
      }

      if ( !Utils.isEmpty( versionComment ) ) {
        insertLogEntry( "Save repository element : " + repositoryElement.toString() + " : " + versionComment );
      }

      ObjectId objectId = new StringObjectId( calcObjectId( repositoryElement ) );

      FileObject fileObject = getFileObject( repositoryElement );

      String xml = ( (XMLInterface) repositoryElement ).getXML();

      OutputStream os = KettleVFS.getInstance( DefaultBowl.getInstance() ).getOutputStream( fileObject, false );
      os.write( xml.getBytes( Const.XML_ENCODING ) );
      os.close();

View on GitHub (pinned to f3058517a1)