pentaho/pentaho-kettle · error · KettleDatabaseException

Dynamic driver for ' ' has been unloaded (disconnect was…

Error message

Dynamic driver for '{effectiveClassName}' has been unloaded (disconnect was called concurrently). Reconnect to reload the driver.

What it means

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.

Solutions

  1. Reconnect — a fresh connect() reloads the dynamic driver automatically
  2. Ensure each Database instance is used by a single thread or properly synchronized
  3. Avoid calling disconnect() while connect() is in flight on the same Database object
  4. Do not share one Database instance across concurrently executing transformations/jobs

Example fix

// before
new Thread(() -> db.disconnect()).start();
Connection c = db.getConnection(); // races disconnect
// after
db.disconnect(); // ensure fully closed
Database db2 = new Database(...); db2.connect(); // fresh instance
Defensive patterns

Strategy: try-catch

Try / catch

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; }

Prevention

When it happens

Trigger: Calling connect() on a Database whose disconnect() runs concurrently (or already ran) so dynamicDriver was cleared to null before openConnectionViaDynamicDriver reads it.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/cc68c2146f65e415. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:939

          } catch ( Exception ignored ) {
            // best-effort
          }
        }
        throw new KettleDatabaseException(
          "Dynamic driver: failed to load '" + effectiveClassName + "' from '" + resolvedPath + "': " + e.getMessage(), e );
      }
    }
  }

  /**
   * Opens a JDBC connection via the already-loaded {@link #dynamicDriver}, bypassing
   * {@link DriverManager}. Validates URL acceptance before connecting.
   */
  private Connection openConnectionViaDynamicDriver( String effectiveClassName, String url, Properties properties )
    throws KettleDatabaseException {
    Driver localDriver = dynamicDriver.get();
    if ( localDriver == null ) {
      throw new KettleDatabaseException(
        "Dynamic driver for '" + effectiveClassName + "' has been unloaded (disconnect was called concurrently). "
          + "Reconnect to reload the driver." );
    }
    boolean accepts;
    try {
      accepts = localDriver.acceptsURL( url );
    } catch ( Exception e ) {
      throw new KettleDatabaseException(
        "Dynamic driver '" + effectiveClassName + "' threw exception checking URL '"
          + url + "': " + errorMsg( e ), e );
    }
    if ( !accepts ) {
      throw new KettleDatabaseException(
        "Dynamic driver '" + effectiveClassName + "' does not accept URL: " + url
          + " — check the JDBC URL format." );
    }
    try {
      Connection c = localDriver.connect( url, properties );

View on GitHub (pinned to f3058517a1)