pentaho/pentaho-kettle · error · ConverterException

KettleMissingPluginsException( getErrorMessage(…

Error message

KettleMissingPluginsException( getErrorMessage( jobMeta.getMissingEntries() ) )

What it means

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.

Solutions

  1. Install the missing plugins listed in the error message into the Kettle plugins directory and restart
  2. Import into an environment matching the source installation's plugin set, or strip/replace missing plugin entries in the job XML
  3. Check plugin versions/folders (e.g. under plugins/) for the referenced IDs and correct any misnamed directories
  4. If a plugin was intentionally removed, edit the job XML to remove or replace those job entries before import

Example fix

// before: import fails at runtime
NodeRepositoryFileData data = new StreamToJobNodeImporter(...).convert( inputStream, repo );
// after: pre-validate the XML for missing plugins
JobMeta meta = new JobMeta();
meta.loadXML( doc.getDocumentElement(), repo, null );
if ( meta.hasMissingPlugins() ) { installPlugins( meta.getMissingEntries() ); }
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-scan job XML for plugin IDs before import
Document doc = parseXml( jobXml );
JobMeta probe = new JobMeta();
probe.loadXML( doc.getDocumentElement(), repository, null );
if ( probe.hasMissingPlugins() ) { installPlugins( probe.getMissingEntries() ); }

Try / catch

try {
  NodeRepositoryFileData data = converter.convert( stream, repository );
} catch ( ConverterException e ) {
  if ( e.getCause() instanceof KettleMissingPluginsException ) {
    KettleMissingPluginsException mpe = (KettleMissingPluginsException) e.getCause();
    reportMissingPlugins( mpe.getMessage() );
  } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at plugins/pur/core/src/main/java/com/pentaho/repository/importexport/StreamToJobNodeConverter.java:158

   * @param charset
   * @param mimeType
   * @return
   */
  public IRepositoryFileData convert( final InputStream inputStream, final String charset, final String mimeType ) {
    try {
      BoundedInputStream bis = BoundedInputStream.builder().setInputStream( inputStream ).get();

      JobMeta jobMeta = new JobMeta();
      Repository repository = connectToRepository();
      jobMeta.setRepository( repository );
      Document doc = PDIImportUtil.loadXMLFrom( bis );
      if ( doc != null ) {
        jobMeta.loadXML( doc.getDocumentElement(), repository, null );
        if ( jobMeta.hasMissingPlugins() ) {
          KettleMissingPluginsException
            missingPluginsException =
            new KettleMissingPluginsException( getErrorMessage( jobMeta.getMissingEntries() ) );
          throw new ConverterException( missingPluginsException );
        }
        JobDelegate delegate = new JobDelegate( repository, this.unifiedRepository );
        SharedObjectUtil.moveAllSharedObjects( jobMeta, repository.getBowl() );
        SharedObjectUtil.patchDatabaseConnections( repository.getBowl(), jobMeta );
        delegate.saveSharedObjects( jobMeta, null );
        return new NodeRepositoryFileData( delegate.elementToDataNode( jobMeta ), bis.getCount() );
      } else {
        return null;
      }
    } catch ( IOException | KettleException e ) {
      return null;
    }
  }

  private String getErrorMessage( List<MissingEntry> missingEntries ) {
    StringBuilder entries = new StringBuilder();
    for ( MissingEntry entry : missingEntries ) {
      entries.append( "- " + entry.getName() + " - " + entry.getMissingPluginId() + "\n" );

View on GitHub (pinned to f3058517a1)