{"record":{"id":"e12dc623dee2dac0","repo":"pentaho/pentaho-kettle","slug":"kettlemissingpluginsexception-geterrormessage-transmeta","errorCode":null,"errorMessage":"KettleMissingPluginsException( getErrorMessage( transMeta.getMissingTrans() ) )","messagePattern":"KettleMissingPluginsException\\( getErrorMessage\\( transMeta\\.getMissingTrans\\(\\) \\) \\)","errorType":"exception","errorClass":"ConverterException","httpStatus":null,"severity":"error","filePath":"plugins/pur/core/src/main/java/com/pentaho/repository/importexport/StreamToTransNodeConverter.java","lineNumber":148,"sourceCode":"  Repository connectToRepository() throws KettleException {\n    return PDIImportUtil.connectToRepository( null );\n  }\n\n  public IRepositoryFileData convert( final InputStream inputStream, final String charset, final String mimeType ) {\n    try {\n      BoundedInputStream bis = BoundedInputStream.builder().setInputStream( inputStream ).get();\n\n      TransMeta transMeta = new TransMeta();\n      Repository repository = connectToRepository();\n      transMeta.setRepository( repository );\n      Document doc = PDIImportUtil.loadXMLFrom( bis );\n      transMeta.loadXML( doc.getDocumentElement(), repository, false );\n\n      if ( transMeta.hasMissingPlugins() ) {\n        KettleMissingPluginsException\n          missingPluginsException =\n          new KettleMissingPluginsException( getErrorMessage( transMeta.getMissingTrans() ) );\n        throw new ConverterException( missingPluginsException );\n      }\n\n      TransDelegate delegate = new TransDelegate( repository, this.unifiedRepository );\n      SharedObjectUtil.moveAllSharedObjects( transMeta, repository.getBowl() );\n      SharedObjectUtil.patchDatabaseConnections( repository.getBowl(), transMeta );\n      saveSharedObjects( repository, transMeta );\n      return new NodeRepositoryFileData( delegate.elementToDataNode( transMeta ), bis.getCount() );\n    } catch ( IOException | KettleException e ) {\n      logger.error( e );\n      return null;\n    }\n  }\n\n  private String getErrorMessage( List<MissingTrans> missingTrans ) {\n    StringBuilder entries = new StringBuilder();\n    for ( MissingTrans entry : missingTrans ) {\n      entries.append( \"- \" + entry.getStepName() + \" - \" + entry.getMissingPluginId() + \"\\n\" );\n      if ( missingTrans.indexOf( entry ) == missingTrans.size() - 1 ) {","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/pur/core/src/main/java/com/pentaho/repository/importexport/StreamToTransNodeConverter.java#L130-L166","documentation":"StreamToTransNodeConverter.convert imports a transformation XML into the repository. After transMeta.loadXML it checks hasMissingPlugins(); if the transformation references plugin step types not present locally, it builds a KettleMissingPluginsException with getErrorMessage(transMeta.getMissingTrans()) and wraps it in a ConverterException, aborting the import so a broken transformation is never saved.","triggerScenarios":"convert() is called with transformation XML referencing step/plugin IDs missing from the local installation: loadXML succeeds, transMeta.hasMissingPlugins() is true, and the wrapped ConverterException is thrown at line ~148.","commonSituations":"Migrating transformations between Pentaho servers where the target lacks the source's installed step plugins (e.g. big-data or marketplace steps); post-upgrade plugin removal; deploying to a lightweight runtime without the full plugin set.","solutions":["Install the missing step plugins named in the error into the target Kettle plugins directory and restart","Import on an environment whose plugin set matches the source, or remove/replace missing steps in the transformation XML","Verify plugin folder names and versions so the referenced plugin IDs resolve at load time","Re-export the transformation after ensuring all steps are available, then retry the import"],"exampleFix":"// before: import aborts on missing steps\nNodeRepositoryFileData data = converter.convert( stream, repository );\n// after: check for missing plugins first\nif ( transMeta.hasMissingPlugins() ) { logMissing( transMeta.getMissingTrans() ); installPlugins( transMeta.getMissingTrans() ); }\ndata = converter.convert( stream, repository );","handlingStrategy":"try-catch","validationCode":"// pre-scan transformation XML for missing step plugins\nTransMeta probe = new TransMeta();\nprobe.loadXML( doc.getDocumentElement(), repository, false );\nif ( probe.hasMissingPlugins() ) { installPlugins( probe.getMissingTrans() ); }","typeGuard":null,"tryCatchPattern":"try {\n  NodeRepositoryFileData data = converter.convert( stream, repository );\n} catch ( ConverterException e ) {\n  if ( e.getCause() instanceof KettleMissingPluginsException ) {\n    KettleMissingPluginsException mpe = (KettleMissingPluginsException) e.getCause();\n    installMissingStepPlugins( mpe.getMessage() );\n  } else { throw e; }\n}","preventionTips":["Inventory step plugins on the export environment and install all of them on the import environment","Verify plugin folders exist and are correctly named after upgrades","Catch ConverterException and check getCause() for the missing-trans list before retrying","Use marketplace/plugin management tooling to keep environments consistent"],"tags":["kettle","plugins","transformation","import"],"backgroundTag":"missing-dependency","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"}