{"record":{"id":"119ebb9f5222f279","repo":"pentaho/pentaho-kettle","slug":"class-repositoryelement-getclass-getname-needs-to-implement","errorCode":null,"errorMessage":"Class [ + repositoryElement.getClass().getName() + ] needs to implement the XML Interface in order to save it to disk","messagePattern":"Class \\[ \\+ repositoryElement\\.getClass\\(\\)\\.getName\\(\\) \\+ \\] needs to implement the XML Interface in order to save it to disk","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/repository/filerep/KettleFileRepository.java","lineNumber":304,"sourceCode":"  @Override\n  public void save( RepositoryElementInterface repositoryElement, String versionComment,\n    ProgressMonitorListener monitor, boolean overwrite ) throws KettleException {\n    // We always overwrite so no further changes necessary\n    save( repositoryElement, versionComment, monitor, null, overwrite );\n  }\n\n  @Override\n  public void save( RepositoryElementInterface repositoryElement, String versionComment, Calendar versionDate,\n    ProgressMonitorListener monitor, boolean overwrite ) throws KettleException {\n    save( repositoryElement, versionComment, monitor, null, overwrite );\n  }\n\n  public void save( RepositoryElementInterface repositoryElement, String versionComment,\n    ProgressMonitorListener monitor, ObjectId parentId, boolean used ) throws KettleException {\n    try {\n      if ( !( repositoryElement instanceof XMLInterface )\n        && !( repositoryElement instanceof SharedObjectInterface ) ) {\n        throw new KettleException( \"Class [\"\n          + repositoryElement.getClass().getName()\n          + \"] needs to implement the XML Interface in order to save it to disk\" );\n      }\n\n      if ( !Utils.isEmpty( versionComment ) ) {\n        insertLogEntry( \"Save repository element : \" + repositoryElement.toString() + \" : \" + versionComment );\n      }\n\n      ObjectId objectId = new StringObjectId( calcObjectId( repositoryElement ) );\n\n      FileObject fileObject = getFileObject( repositoryElement );\n\n      String xml = ( (XMLInterface) repositoryElement ).getXML();\n\n      OutputStream os = KettleVFS.getInstance( DefaultBowl.getInstance() ).getOutputStream( fileObject, false );\n      os.write( xml.getBytes( Const.XML_ENCODING ) );\n      os.close();\n","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/repository/filerep/KettleFileRepository.java#L286-L322","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Make the element class implement XMLInterface (getXML(), loadXML()) so it can be serialized to disk.","Alternatively implement SharedObjectInterface if the element is a shared object suitable for XML storage.","Store non-XML-serializable objects in the metastore instead of the file repository.","Check the named class in the message — it tells you exactly which custom type lacks the interface."],"exampleFix":"// before\npublic class MyElement implements RepositoryElementInterface { ... }\n\n// after\npublic class MyElement implements RepositoryElementInterface, XMLInterface {\n  public String getXML() { return xml; }\n  public void loadXML(Node node, ...) { ... }\n}","handlingStrategy":"type-guard","validationCode":"boolean savable = element instanceof XMLInterface || element instanceof SharedObjectInterface;","typeGuard":"boolean canSaveToFileRepo(RepositoryElementInterface e) {\n  return e instanceof XMLInterface || e instanceof SharedObjectInterface;\n}","tryCatchPattern":"try {\n  repo.save(element, null, null);\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"needs to implement the XML Interface\")) {\n    log.error(\"Custom element cannot go to file repo: \" + element.getClass().getName());\n  } else { throw e; }\n}","preventionTips":["Implement XMLInterface in any custom repository element meant for file repos","Store non-XML-serializable metadata in the metastore instead","Check the class name in the message to locate the offending type"],"tags":["kettle","file-repository","xml-interface","serialization"],"backgroundTag":"incompatible-source-type","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}