{"record":{"id":"cc68c2146f65e415","repo":"pentaho/pentaho-kettle","slug":"dynamic-driver-for-effectiveclassname-has-been-unloaded","errorCode":null,"errorMessage":"Dynamic driver for '{effectiveClassName}' has been unloaded (disconnect was called concurrently). Reconnect to reload the driver.","messagePattern":"Dynamic driver for '(.+?)' has been unloaded \\(disconnect was called concurrently\\)\\. Reconnect to reload the driver\\.","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/Database.java","lineNumber":939,"sourceCode":"          } catch ( Exception ignored ) {\n            // best-effort\n          }\n        }\n        throw new KettleDatabaseException(\n          \"Dynamic driver: failed to load '\" + effectiveClassName + \"' from '\" + resolvedPath + \"': \" + e.getMessage(), e );\n      }\n    }\n  }\n\n  /**\n   * Opens a JDBC connection via the already-loaded {@link #dynamicDriver}, bypassing\n   * {@link DriverManager}. Validates URL acceptance before connecting.\n   */\n  private Connection openConnectionViaDynamicDriver( String effectiveClassName, String url, Properties properties )\n    throws KettleDatabaseException {\n    Driver localDriver = dynamicDriver.get();\n    if ( localDriver == null ) {\n      throw new KettleDatabaseException(\n        \"Dynamic driver for '\" + effectiveClassName + \"' has been unloaded (disconnect was called concurrently). \"\n          + \"Reconnect to reload the driver.\" );\n    }\n    boolean accepts;\n    try {\n      accepts = localDriver.acceptsURL( url );\n    } catch ( Exception e ) {\n      throw new KettleDatabaseException(\n        \"Dynamic driver '\" + effectiveClassName + \"' threw exception checking URL '\"\n          + url + \"': \" + errorMsg( e ), e );\n    }\n    if ( !accepts ) {\n      throw new KettleDatabaseException(\n        \"Dynamic driver '\" + effectiveClassName + \"' does not accept URL: \" + url\n          + \" — check the JDBC URL format.\" );\n    }\n    try {\n      Connection c = localDriver.connect( url, properties );","sourceCodeStart":921,"sourceCodeEnd":957,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/Database.java#L921-L957","documentation":"The dynamic driver instance is held in a per-connection AtomicReference (dynamicDriver). openConnectionViaDriver requires it to be non-null; if another thread called disconnect() concurrently the driver was unloaded and this error is thrown instead of dereferencing null. It is a race/-state error indicating the connection is closing while a connect is still in flight.","triggerScenarios":"Calling connect() on a Database whose disconnect() runs concurrently (or already ran) so dynamicDriver was cleared to null before openConnectionViaDynamicDriver reads it.","commonSituations":"Trans pipelines canceling/aborting a step while it is still opening the connection; timeout watchdog closing connections; double lifecycle management (framework and user code both calling disconnect); shared Database instance across threads.","solutions":["Reconnect — a fresh connect() reloads the dynamic driver automatically","Ensure each Database instance is used by a single thread or properly synchronized","Avoid calling disconnect() while connect() is in flight on the same Database object","Do not share one Database instance across concurrently executing transformations/jobs"],"exampleFix":"// before\nnew Thread(() -> db.disconnect()).start();\nConnection c = db.getConnection(); // races disconnect\n// after\ndb.disconnect(); // ensure fully closed\nDatabase db2 = new Database(...); db2.connect(); // fresh instance","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { conn = db.getConnection(); } catch (KettleDatabaseException e) { if (e.getMessage().contains(\"has been unloaded (disconnect was called concurrently)\")) { log.warn(\"Concurrent disconnect during connect — reconnecting\"); db = new Database(...); conn = db.getConnection(); } else throw e; }","preventionTips":["Use each Database instance from a single thread","Do not call disconnect() while connect()/getConnection() is in flight","Centralize connection lifecycle management (one owner per connection)","Avoid sharing Database instances across steps/threads"],"tags":["jdbc","concurrency","race-condition","lifecycle"],"backgroundTag":"invalid-state-transition","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"}