{"record":{"id":"a36a4f4f06a8b4b1","repo":"pentaho/pentaho-kettle","slug":"unable-to-load-class-classname","errorCode":null,"errorMessage":"Unable to load class: ${className}","messagePattern":"Unable to load class: (.+?)","errorType":"exception","errorClass":"KettlePluginException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/plugins/BasePluginType.java","lineNumber":849,"sourceCode":"   * in the lib directory of plugin folders.\n   *\n   * @param transverseLibDirs\n   */\n  protected void setTransverseLibDirs( boolean transverseLibDirs ) {\n    this.searchLibDir = transverseLibDirs;\n  }\n\n  protected void registerPluginJars() throws KettlePluginException {\n    List<JarFileAnnotationPlugin> jarFilePlugins = findAnnotatedClassFiles( pluginClass.getName() );\n    for ( JarFileAnnotationPlugin jarFilePlugin : jarFilePlugins ) {\n\n      URLClassLoader urlClassLoader =\n        createUrlClassLoader( jarFilePlugin.getJarFile(), getClass().getClassLoader() );\n\n      try {\n        Class<?> clazz = urlClassLoader.loadClass( jarFilePlugin.getClassName() );\n        if ( clazz == null ) {\n          throw new KettlePluginException( \"Unable to load class: \" + jarFilePlugin.getClassName() );\n        }\n        List<String> libraries = Arrays.stream( urlClassLoader.getURLs() )\n          .map( URL::getFile )\n          .collect( Collectors.toList() );\n        Annotation annotation = clazz.getAnnotation( pluginClass );\n\n        handlePluginAnnotation( clazz, annotation, libraries, false, jarFilePlugin.getPluginFolder() );\n      } catch ( Exception e ) {\n        // Ignore for now, don't know if it's even possible.\n        LogChannel.GENERAL.logError(\n          \"Unexpected error registering jar plugin file: \" + jarFilePlugin.getJarFile(), e );\n      } finally {\n        if ( urlClassLoader instanceof KettleURLClassLoader ) {\n          ( (KettleURLClassLoader) urlClassLoader ).closeClassLoader();\n        }\n      }\n    }\n  }","sourceCodeStart":831,"sourceCodeEnd":867,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/plugins/BasePluginType.java#L831-L867","documentation":"When scanning a jar-based plugin, BasePluginType loads the plugin's main class with a URLClassLoader built over the plugin jar. If loadClass returns null (or otherwise fails to resolve), KettlePluginException 'Unable to load class: <className>' is thrown. This means the jar declares a plugin main class that cannot actually be loaded from that jar's classloader.","triggerScenarios":"searchPlugins()/jar scanning -> new BasePluginType(...)/registerPluginJars where JarFilePlugin.getClassName() names a class absent from the jar, incompatible with the current JVM (bad bytecode version), or whose dependencies are missing so loadClass fails.","commonSituations":"Plugin jar built for a different Kettle version; incomplete plugin folder missing dependency jars; Java version mismatch (e.g. class compiled for Java 17 on Java 11 runtime); fat-jar shading that stripped plugin classes.","solutions":["Verify the class named in the message actually exists in the plugin jar (jar tf plugin.jar | grep ClassName).","Add the plugin's missing dependency jars to its lib folder or the Kettle classpath.","Rebuild the plugin against your Kettle/JDK version, or run Kettle on the JDK version the plugin was compiled for.","Replace the plugin jar with a complete, version-compatible build."],"exampleFix":"// before\nplugins/myplugin/\n  myplugin.jar        // com.acme.Main missing (incomplete build)\n// after\nplugins/myplugin/\n  myplugin.jar        // contains com.acme.Main\n  lib/dependency.jar","handlingStrategy":"validation","validationCode":"File jar = new File(jarPath);\ntry (java.util.jar.JarFile jf = new java.util.jar.JarFile(jar)) {\n  if (jf.getJarEntry(className.replace('.', '/') + \".class\") == null) {\n    throw new IllegalStateException(\"Class missing from plugin jar: \" + className);\n  }\n}","typeGuard":"static boolean classLoadable(String className, ClassLoader cl) {\n  try { Class.forName(className, false, cl); return true; }\n  catch (Throwable t) { return false; }\n}","tryCatchPattern":"try {\n  pluginType.searchPlugins();\n} catch (KettlePluginException e) {\n  log.logError(\"Plugin class could not be loaded: \" + e.getMessage(), e);\n}","preventionTips":["Verify plugin main class exists in the jar before deploying (jar tf).","Ship all dependency jars alongside the plugin (lib folder).","Match the plugin's target JDK bytecode version to the runtime JVM.","Build plugins against the same Kettle version as the runtime."],"tags":["kettle","plugins","classloader","classpath"],"backgroundTag":"class-not-found","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}