{"record":{"id":"56e36302341dd250","repo":"pentaho/pentaho-kettle","slug":"kettlemissingpluginsexception-geterrormessage-jobmeta","errorCode":null,"errorMessage":"KettleMissingPluginsException( getErrorMessage( jobMeta.getMissingEntries() ) )","messagePattern":"KettleMissingPluginsException\\( getErrorMessage\\( jobMeta\\.getMissingEntries\\(\\) \\) \\)","errorType":"exception","errorClass":"ConverterException","httpStatus":null,"severity":"error","filePath":"plugins/pur/core/src/main/java/com/pentaho/repository/importexport/StreamToJobNodeConverter.java","lineNumber":158,"sourceCode":"   * @param charset\n   * @param mimeType\n   * @return\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      JobMeta jobMeta = new JobMeta();\n      Repository repository = connectToRepository();\n      jobMeta.setRepository( repository );\n      Document doc = PDIImportUtil.loadXMLFrom( bis );\n      if ( doc != null ) {\n        jobMeta.loadXML( doc.getDocumentElement(), repository, null );\n        if ( jobMeta.hasMissingPlugins() ) {\n          KettleMissingPluginsException\n            missingPluginsException =\n            new KettleMissingPluginsException( getErrorMessage( jobMeta.getMissingEntries() ) );\n          throw new ConverterException( missingPluginsException );\n        }\n        JobDelegate delegate = new JobDelegate( repository, this.unifiedRepository );\n        SharedObjectUtil.moveAllSharedObjects( jobMeta, repository.getBowl() );\n        SharedObjectUtil.patchDatabaseConnections( repository.getBowl(), jobMeta );\n        delegate.saveSharedObjects( jobMeta, null );\n        return new NodeRepositoryFileData( delegate.elementToDataNode( jobMeta ), bis.getCount() );\n      } else {\n        return null;\n      }\n    } catch ( IOException | KettleException e ) {\n      return null;\n    }\n  }\n\n  private String getErrorMessage( List<MissingEntry> missingEntries ) {\n    StringBuilder entries = new StringBuilder();\n    for ( MissingEntry entry : missingEntries ) {\n      entries.append( \"- \" + entry.getName() + \" - \" + entry.getMissingPluginId() + \"\\n\" );","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/pur/core/src/main/java/com/pentaho/repository/importexport/StreamToJobNodeConverter.java#L140-L176","documentation":"StreamToJobNodeConverter.convert imports a job XML into a Pentaho repository. After loadXML it checks jobMeta.hasMissingPlugins(); if the job references plugin step/entry types not installed in this Kettle installation, it builds a KettleMissingPluginsException listing the missing entries and wraps it in a ConverterException so the import aborts instead of saving a broken job.","triggerScenarios":"convert() is called with job XML whose metadata references plugin IDs absent from the local plugins directory: jobMeta.loadXML succeeds, hasMissingPlugins() returns true, and getErrorMessage(jobMeta.getMissingEntries()) is wrapped into ConverterException.","commonSituations":"Importing a job exported from another Pentaho/Kettle installation with additional marketplace plugins; running a stripped-down/karaf-minimal distribution missing plugin folders; plugin version mismatches after upgrade leaving plugin IDs unresolvable.","solutions":["Install the missing plugins listed in the error message into the Kettle plugins directory and restart","Import into an environment matching the source installation's plugin set, or strip/replace missing plugin entries in the job XML","Check plugin versions/folders (e.g. under plugins/) for the referenced IDs and correct any misnamed directories","If a plugin was intentionally removed, edit the job XML to remove or replace those job entries before import"],"exampleFix":"// before: import fails at runtime\nNodeRepositoryFileData data = new StreamToJobNodeImporter(...).convert( inputStream, repo );\n// after: pre-validate the XML for missing plugins\nJobMeta meta = new JobMeta();\nmeta.loadXML( doc.getDocumentElement(), repo, null );\nif ( meta.hasMissingPlugins() ) { installPlugins( meta.getMissingEntries() ); }","handlingStrategy":"try-catch","validationCode":"// pre-scan job XML for plugin IDs before import\nDocument doc = parseXml( jobXml );\nJobMeta probe = new JobMeta();\nprobe.loadXML( doc.getDocumentElement(), repository, null );\nif ( probe.hasMissingPlugins() ) { installPlugins( probe.getMissingEntries() ); }","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    reportMissingPlugins( mpe.getMessage() );\n  } else { throw e; }\n}","preventionTips":["Keep plugin sets in sync across source and target Kettle installations","Unzip all required plugins into plugins/ and restart before importing","Catch ConverterException and inspect getCause() for KettleMissingPluginsException to get the exact missing-entry list","Avoid stripping plugin directories when creating deployment images"],"tags":["kettle","plugins","import","missing-dependency"],"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"}