pentaho/pentaho-kettle · error · ConverterException

KettleMissingPluginsException( getErrorMessage(…

Error message

KettleMissingPluginsException( getErrorMessage( transMeta.getMissingTrans() ) )

What it means

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.

Solutions

  1. Install the missing step plugins named in the error into the target Kettle plugins directory and restart
  2. Import on an environment whose plugin set matches the source, or remove/replace missing steps in the transformation XML
  3. Verify plugin folder names and versions so the referenced plugin IDs resolve at load time
  4. Re-export the transformation after ensuring all steps are available, then retry the import

Example fix

// before: import aborts on missing steps
NodeRepositoryFileData data = converter.convert( stream, repository );
// after: check for missing plugins first
if ( transMeta.hasMissingPlugins() ) { logMissing( transMeta.getMissingTrans() ); installPlugins( transMeta.getMissingTrans() ); }
data = converter.convert( stream, repository );
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-scan transformation XML for missing step plugins
TransMeta probe = new TransMeta();
probe.loadXML( doc.getDocumentElement(), repository, false );
if ( probe.hasMissingPlugins() ) { installPlugins( probe.getMissingTrans() ); }

Try / catch

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

Prevention

When it happens

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

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

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/e12dc623dee2dac0. Report an issue: GitHub.

Appendix: source

Thrown at plugins/pur/core/src/main/java/com/pentaho/repository/importexport/StreamToTransNodeConverter.java:148

  Repository connectToRepository() throws KettleException {
    return PDIImportUtil.connectToRepository( null );
  }

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

      TransMeta transMeta = new TransMeta();
      Repository repository = connectToRepository();
      transMeta.setRepository( repository );
      Document doc = PDIImportUtil.loadXMLFrom( bis );
      transMeta.loadXML( doc.getDocumentElement(), repository, false );

      if ( transMeta.hasMissingPlugins() ) {
        KettleMissingPluginsException
          missingPluginsException =
          new KettleMissingPluginsException( getErrorMessage( transMeta.getMissingTrans() ) );
        throw new ConverterException( missingPluginsException );
      }

      TransDelegate delegate = new TransDelegate( repository, this.unifiedRepository );
      SharedObjectUtil.moveAllSharedObjects( transMeta, repository.getBowl() );
      SharedObjectUtil.patchDatabaseConnections( repository.getBowl(), transMeta );
      saveSharedObjects( repository, transMeta );
      return new NodeRepositoryFileData( delegate.elementToDataNode( transMeta ), bis.getCount() );
    } catch ( IOException | KettleException e ) {
      logger.error( e );
      return null;
    }
  }

  private String getErrorMessage( List<MissingTrans> missingTrans ) {
    StringBuilder entries = new StringBuilder();
    for ( MissingTrans entry : missingTrans ) {
      entries.append( "- " + entry.getStepName() + " - " + entry.getMissingPluginId() + "\n" );
      if ( missingTrans.indexOf( entry ) == missingTrans.size() - 1 ) {

View on GitHub (pinned to f3058517a1)