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
- 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
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
- 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
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
- KettleMissingPluginsException( getErrorMessage(…
- A deadlock was detected between steps
- AggregateRowsMeta.Exception.UnableToLoadStepInfo
- AppendMeta.Exception.UnableToLoadStepInfo
- At this time we don't support the use of multiple cluster…
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)