pentaho/pentaho-kettle · error · KettleDatabaseException
JdbcDriverResolver: driver JAR '" + driverId + ".jar" + "'…
Error message
JdbcDriverResolver: driver JAR '" + driverId + ".jar" + "' not found at any known location Set environment variable or system property 'JDBC_DRIVER_SERVICE_URL' to enable automatic download from the connection-management service.
What it means
JdbcDriverResolver.downloadFromService() is the last step of the resolution chain. When the driver JAR was not found locally or in the drivers directory, it tries to download it from a connection-management service. If neither the JDBC_DRIVER_SERVICE_URL environment variable nor the equivalent system property is set, it cannot download and throws this KettleDatabaseException.
Solutions
- Set JDBC_DRIVER_SERVICE_URL (env var or -D system property) to the base URL of the connection-management service
- Or manually place <driverId>.jar into the directory named by JDBC_DRIVERS_DIRECTORY
- Or bundle the JAR in lib/ so step 1 of resolve() finds it at the configured path
- Enable dynamic driver caching so a one-time download persists for later runs
Example fix
// before $ kettle.sh # JDBC_DRIVER_SERVICE_URL unset → download impossible // after export JDBC_DRIVER_SERVICE_URL=https://driver-service.internal.example.com kettle.sh
Defensive patterns
Strategy: fallback
Validate before calling
String url = System.getenv( "JDBC_DRIVER_SERVICE_URL" ); if ( url == null || url.trim().isEmpty() ) url = System.getProperty( "JDBC_DRIVER_SERVICE_URL" ); boolean downloadAvailable = url != null && !url.trim().isEmpty();
Try / catch
try { path = JdbcDriverResolver.resolve( driverId ); } catch ( KettleDatabaseException e ) { if ( e.getMessage().contains( "JDBC_DRIVER_SERVICE_URL" ) ) { /* fall back to bundled driver or abort with setup instructions */ } throw e; } Prevention
- Set JDBC_DRIVER_SERVICE_URL in all deployment environments (image env, kettle.properties)
- Pre-bundle common driver JARs so download is never needed
- Document the env var in deployment runbooks
- Verify provisioning with a startup health check
When it happens
Trigger: resolve(driverId) found the JAR at no configured path, no drivers directory, and no cached copy, and Const.getJdbcDriverServiceUrl() returned null/blank because JDBC_DRIVER_SERVICE_URL is unset in the environment.
Common situations: Fresh installation where the JDBC driver was never bundled; container image lacking both the driver JAR and the service URL; kettle.properties/env not provisioned in CI; typo in the environment variable name.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Database.Exception.UnableToGetMetadata
- DynamicDriverCache: failed to load driver '" +…
- Error connecting to database
- JdbcDriverResolver: driverId must not be null or blank
- JdbcDriverResolver: JAR not found: " + jarAbsolutePath
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/05d605670c76a07e.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/JdbcDriverResolver.java:244
* <p>The download base URL is read from:
* <ol>
* <li>Environment variable {@code JDBC_DRIVER_SERVICE_URL}</li>
* <li>System property {@code JDBC_DRIVER_SERVICE_URL}</li>
* </ol>
* The JAR is fetched from {@code <baseUrl>/api/v1/connection-drivers/<driverId>/download}.
*
* @param driverId id of the JDBC driver to download from connection-management service
* @return absolute path of the downloaded JAR
* @throws KettleDatabaseException if the download URL is not configured or the download fails
*/
private static String downloadFromService( String driverId )
throws KettleDatabaseException {
// Const.getJdbcDriverServiceUrl() applies NVL(getenv, getProperty) — works on all environments.
String serviceBaseUrl = Const.getJdbcDriverServiceUrl();
if ( serviceBaseUrl == null || serviceBaseUrl.trim().isEmpty() ) {
throw new KettleDatabaseException(
"JdbcDriverResolver: driver JAR '" + driverId + ".jar" + "' not found at any known location "
+ "Set environment variable or system property 'JDBC_DRIVER_SERVICE_URL'"
+ " to enable automatic download from the connection-management service." );
}
// One lock per JAR name — threads for *different* JARs never block each other.
ReentrantLock lock = DOWNLOAD_LOCKS.computeIfAbsent( driverId + ".jar", k -> new ReentrantLock() );
lock.lock();
try {
Path saveDir = resolveWritableSaveDir();
Path savePath = saveDir.resolve( driverId + ".jar" );
// Re-check after acquiring the lock: a waiting thread may find the file was already
// downloaded by the thread that held the lock before it.
if ( Files.isRegularFile( savePath ) ) {
log.logBasic( "JdbcDriverResolver: '" + driverId + ".jar" + "' already downloaded by concurrent thread → "
+ savePath );
return savePath.toAbsolutePath().toString();View on GitHub (pinned to f3058517a1)