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
- 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
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
- 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
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
- KettleMissingPluginsException( getErrorMessage(…
- No ID specified for plugin with class
- Not a valid id specified in plugin
- Plugin's plugin.properties file could not be read.
- PLUGIN0001
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)