pentaho/pentaho-kettle · error · KettleException
Unable to find image file
Error message
Unable to find image file: <imageFile> for plugin: <plugin>
What it means
Thrown by SwingGUIResource.loadEntryImages when the plugin registry reports an image file for a job/plugin entry but SwingGUIResource.getUniversalImageIcon cannot resolve it to a SwingUniversalImage (returned null). Pentaho Kettle loads all entry/step icons at GUI startup into a map keyed by plugin id; a missing icon breaks GUI resource initialization.
Solutions
- Verify the imageFile path declared by the plugin exists on the classpath or inside the plugin jar/zip at the exact path
- Fix the plugin.xml image-file entry or @Injection/@Step metadata to point at the actual icon resource
- Rebuild/redeploy the plugin including its resources (icons often excluded by build filters)
- Clear the plugin cache folder and restart so stale plugin folders are re-scanned
Example fix
// before (plugin.xml) <image-file>icons/wrng.png</image-file> // after <image-file>icons/wrong.png</image-file>
Defensive patterns
Strategy: validation
Validate before calling
String img = plugin.getImageFile();
if (img == null || getClass().getResourceAsStream(img) == null && !new java.io.File(img).exists()) {
throw new IllegalStateException("Icon resource missing for plugin " + plugin.getIds()[0] + ": " + img);
} Try / catch
try { SwingUniversalImage image = getUniversalImageIcon(plugin); }
catch (KettleException e) { log.logError("Skipping icon for " + plugin.getIds()[0], e); continue; } Prevention
- Keep icons under src/main/resources so build tools package them
- Verify plugin jars contain the declared image paths before deployment
- Diff plugin.xml image-file entries against actual packaged files in CI
When it happens
Trigger: A plugin declares an imageFile in its plugin.xml/annotation that does not exist on the classpath or in the plugin's jar/folder, so getUniversalImageIcon returns null after exhausting all lookup locations.
Common situations: Hand-written plugin.xml with a typo in <image-file>; plugin jar repackaged without image resources; renamed/moved icon files after an upgrade; plugin folder copied without resource files.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Unable to find file: for plugin
- Unable to load image from file
- Bounds of this rule are not numeric: lowerBound=
- ConnectionFileObject.PVFSRoot.UnsupportedOperation
- ConnectionFileObject.UndefinedConnection
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/1440246c2fa6c793.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/core/gui/SwingGUIResource.java:91
+ plugin.getName() + " (id=" + plugin.getIds()[0] + ")", e );
}
}
return map;
}
private Map<String, SwingUniversalImage> loadEntryImages() {
Map<String, SwingUniversalImage> map = new HashMap<>();
for ( PluginInterface plugin : PluginRegistry.getInstance().getPlugins( JobEntryPluginType.class ) ) {
try {
if ( JobMeta.STRING_SPECIAL.equals( plugin.getIds()[0] ) ) {
continue;
}
SwingUniversalImage image = getUniversalImageIcon( plugin );
if ( image == null ) {
throw new KettleException( "Unable to find image file: "
+ plugin.getImageFile() + " for plugin: " + plugin );
}
map.put( plugin.getIds()[0], image );
} catch ( Exception e ) {
log.logError( "Unable to load job entry icon image for plugin: "
+ plugin.getName() + " (id=" + plugin.getIds()[0] + ")", e );
}
}
return map;
}
private SwingUniversalImage getUniversalImageIcon( PluginInterface plugin ) throws KettleException {
try {
PluginRegistry registry = PluginRegistry.getInstance();
String filename = plugin.getImageFile();
View on GitHub (pinned to f3058517a1)