pentaho/pentaho-kettle · error · KettleDatabaseException
Database.Exception.UnableToFindClassMissingDriver
Error message
Database.Exception.UnableToFindClassMissingDriver (i18n: Unable to find driver class {0} - missing from plugin {1}) What it means
loadStaticDriver throws KettleDatabaseException with i18n key "Database.Exception.UnableToFindClassMissingDriver" ("Unable to find driver class {0} - missing from plugin {1}") when Class.forName (or the driver's static registration block) raises ClassNotFoundException or NoClassDefFoundError. The driver jar is simply not on the classpath.
Solutions
- Download the correct JDBC driver and place its jar in the Kettle lib/ or plugins/<db-plugin>/lib directory
- Verify the driver class name matches the jar (e.g. org.postgresql.Driver for postgresql-*.jar)
- If embedding, ensure the driver is included in the packaged classpath
- Restart the application so the dynamic class loader picks up newly added jars
Example fix
// before classpath: kettle-core.jar, kettle-engine.jar // no postgres driver // after classpath: kettle-core.jar, kettle-engine.jar, postgresql-42.7.3.jar
Defensive patterns
Strategy: validation
Validate before calling
try {
Class.forName( driverClassname );
} catch ( ClassNotFoundException e ) {
throw new IllegalStateException( "JDBC driver " + driverClassname
+ " missing; add the driver jar to lib/ or the plugin's lib directory" );
} Type guard
boolean driverPresent = Arrays.stream(
System.getProperty( "java.class.path" ).split( File.pathSeparator ) )
.noneMatch( p -> p.contains( "missing-driver" ) ); // or scan for expected jar name Try / catch
try {
db.connect();
} catch ( KettleDatabaseException e ) {
if ( e.getMessage().contains( "missing from plugin" ) ) {
log.error( "Install the JDBC driver jar named in the message into lib/" );
}
} Prevention
- Ship the JDBC driver jar with every deployment (check license terms)
- Verify driver presence at application startup with Class.forName
- Document required driver jars per database type in deployment runbooks
When it happens
Trigger: Connecting with access type Native/JDBC when the JDBC driver class named in the DatabaseMeta cannot be loaded — driver jar absent from the plugin's lib folder or the application classpath.
Common situations: Forgetting to drop the JDBC driver jar into lib/ or the database plugin directory, driver jar excluded from the build (license-based exclusions, e.g. Oracle/MSSQL drivers), fat-jar packaging that omitted the driver.
Related errors
- Dynamic driver: failed to load
- Error creating class for:
- Error creating class for : + ic[i].getName()
- JobEntryLoader was unable to find Job Entry Plugin with…
- KettleMissingPluginsException( getErrorMessage(…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/8b54901f3bca6409.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:654
throw new KettleDatabaseException( "Error connecting to database: (using class " + classname + ")", e );
}
}
private void loadStaticDriver( String classname, PluginInterface plugin ) throws KettleDatabaseException {
try {
synchronized ( java.sql.DriverManager.class ) {
ClassLoader classLoader = PluginRegistry.getInstance().getClassLoader( plugin );
Class<?> driverClass = classLoader.loadClass( classname );
// Only need DelegatingDriver for drivers not from our classloader
if ( driverClass.getClassLoader() != this.getClass().getClassLoader() ) {
registerDelegatingDriver( driverClass );
} else {
// Trigger static register block in driver class
Class.forName( classname );
}
}
} catch ( NoClassDefFoundError | ClassNotFoundException e ) {
throw new KettleDatabaseException( BaseMessages.getString( PKG,
"Database.Exception.UnableToFindClassMissingDriver", classname, plugin.getName() ), e );
} catch ( Exception e ) {
throw new KettleDatabaseException( "Exception while loading class", e );
}
}
private void registerDelegatingDriver( Class<?> driverClass ) throws KettleDatabaseException {
String pluginId =
PluginRegistry.getInstance().getPluginId( DatabasePluginType.class, databaseMeta.getDatabaseInterface() );
Set<String> registeredDriversFromPlugin = registeredDrivers.computeIfAbsent( pluginId, k -> new HashSet<>() );
// Prevent registering multiple delegating drivers for same class, plugin
if ( !registeredDriversFromPlugin.contains( driverClass.getCanonicalName() ) ) {
try {
DriverManager.registerDriver( new DelegatingDriver( (Driver) driverClass.getDeclaredConstructor().newInstance() ) );
} catch ( InstantiationException | IllegalAccessException | NoSuchMethodException | java.lang.reflect.InvocationTargetException | SQLException e ) {
throw new KettleDatabaseException(
"Unable to register delegating driver for class " + driverClass.getCanonicalName(), e );
}View on GitHub (pinned to f3058517a1)