{"record":{"id":"0fd583d37fef8193","repo":"pentaho/pentaho-kettle","slug":"dynamicdrivercache-failed-to-load-driver-driverclassname","errorCode":null,"errorMessage":"DynamicDriverCache: failed to load driver '\" + driverClassName + \"' from '\" + jarAbsolutePath + \"': \" + e.getMessage()","messagePattern":"DynamicDriverCache: failed to load driver '\" \\+ driverClassName \\+ \"' from '\" \\+ jarAbsolutePath \\+ \"': \" \\+ e\\.getMessage\\(\\)","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/DynamicDriverCache.java","lineNumber":227,"sourceCode":"      }\n    } finally {\n      rwLock.readLock().unlock();\n    }\n\n    // 2. Expensive work outside any lock — NFS/SMB reads happen here.\n    log.logBasic( \"DynamicDriverCache: loading \" + driverClassName + \" from \" + jarAbsolutePath + \", \" + extraJarsAbsolutePath );\n\n    List<URL> urls = JdbcDriverResolver.buildUrlList( jarAbsolutePath, extraJarsAbsolutePath );\n    ChildFirstURLClassLoader loader = null;\n    CacheEntry entry;\n    try {\n      loader = new ChildFirstURLClassLoader( urls.toArray( new URL[ 0 ] ), Database.class.getClassLoader() );\n      Class<?> driverClass = loader.loadClass( driverClassName );\n      Driver driver = (Driver) driverClass.getDeclaredConstructor().newInstance();\n      entry = new CacheEntry( loader, driver );\n    } catch ( Exception e ) {\n      closeSilently( loader );\n      throw new KettleDatabaseException(\n        \"DynamicDriverCache: failed to load driver '\" + driverClassName\n          + \"' from '\" + jarAbsolutePath + \"': \" + e.getMessage(), e );\n    }\n\n    // 3. Write lock — double-check, insert, collect oldest entry if over capacity.\n    Driver driverToReturn;\n    rwLock.writeLock().lock();\n    try {\n      CacheEntry existing = cache.get( key );\n      if ( existing != null ) {\n        // Another thread beat us to it — discard our copy, return the winner's Driver.\n        closeSilently( loader );\n        log.logDebug( \"DynamicDriverCache: concurrent load race, discarding duplicate for \" + driverClassName );\n        return existing.driver;\n      }\n      cache.put( key, entry );\n      log.logBasic( \"DynamicDriverCache: cached driver \" + driverClassName + \" @ \" + jarAbsolutePath );\n      driverToReturn = entry.driver;","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/DynamicDriverCache.java#L209-L245","documentation":"DynamicDriverCache.getOrLoadDriver() loads a JDBC driver class from a JAR using a ChildFirstURLClassLoader and instantiates it. If class loading, class cast to java.sql.Driver, or reflective instantiation fails, the loader is closed and a KettleDatabaseException naming the driver class and JAR path is thrown.","triggerScenarios":"Calling getOrLoadDriver with a JAR that does not contain driverClassName; the class exists but does not implement java.sql.Driver; the driver class has no no-arg constructor or its constructor throws; the JAR is corrupt/incompatible with the JVM.","commonSituations":"Wrong driverClassName configured for the JAR (e.g. MySQL Connector 8.x moved to com.mysql.cj.jdbc.Driver); JAR built for a newer Java version than the runtime; truncated or corrupted downloaded JAR.","solutions":["Verify driverClassName matches the actual class inside the JAR (jar tf <jar> | grep -i driver)","Confirm the class implements java.sql.Driver and has a public no-arg constructor","Check the JAR's class file version is compatible with your JVM","Re-download/replace the JAR in case it is corrupt"],"exampleFix":"// before\nDriver d = cache.getOrLoadDriver( \"/opt/jars/mysql.jar\", \"com.mysql.jdbc.Driver\" );\n// after (Connector/J 8.x)\nDriver d = cache.getOrLoadDriver( \"/opt/jars/mysql.jar\", \"com.mysql.cj.jdbc.Driver\" );","handlingStrategy":"try-catch","validationCode":"File jar = new File( jarAbsolutePath );\nif ( !jar.isFile() ) throw new IllegalStateException( \"missing driver JAR: \" + jar );\ntry ( JarFile jf = new JarFile( jar ) ) {\n  if ( jf.getJarEntry( driverClassName.replace( '.', '/' ) + \".class\" ) == null )\n    throw new IllegalStateException( driverClassName + \" not in \" + jar );\n}","typeGuard":"boolean isDriverClass( Class<?> c ) { return java.sql.Driver.class.isAssignableFrom( c ); }","tryCatchPattern":"try { driver = cache.getOrLoadDriver( jar, cls ); } catch ( KettleDatabaseException e ) { log.error( \"driver load failed for \" + cls + \": \" + e.getCause(), e ); }","preventionTips":["Keep a mapping table of databaseType → driverClassName up to date","Verify JARs are complete (checksum) after download","Align JVM version with driver JAR requirements"],"tags":["jdbc","driver","classloader"],"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"}