{"record":{"id":"05d605670c76a07e","repo":"pentaho/pentaho-kettle","slug":"jdbcdriverresolver-driver-jar-driverid-jar-not-found-at-any","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/JdbcDriverResolver.java","lineNumber":244,"sourceCode":"   * <p>The download base URL is read from:\n   * <ol>\n   *   <li>Environment variable {@code JDBC_DRIVER_SERVICE_URL}</li>\n   *   <li>System property {@code JDBC_DRIVER_SERVICE_URL}</li>\n   * </ol>\n   * The JAR is fetched from {@code <baseUrl>/api/v1/connection-drivers/<driverId>/download}.\n   *\n   * @param driverId       id of the JDBC driver to download from connection-management service\n   * @return absolute path of the downloaded JAR\n   * @throws KettleDatabaseException if the download URL is not configured or the download fails\n   */\n  private static String downloadFromService( String driverId )\n    throws KettleDatabaseException {\n\n    // Const.getJdbcDriverServiceUrl() applies NVL(getenv, getProperty) — works on all environments.\n    String serviceBaseUrl = Const.getJdbcDriverServiceUrl();\n\n        if ( serviceBaseUrl == null || serviceBaseUrl.trim().isEmpty() ) {\n            throw new KettleDatabaseException(\n                    \"JdbcDriverResolver: driver JAR '\" + driverId + \".jar\" + \"' not found at any known location \"\n                            + \"Set environment variable or system property 'JDBC_DRIVER_SERVICE_URL'\"\n                            + \" to enable automatic download from the connection-management service.\" );\n        }\n\n        // One lock per JAR name — threads for *different* JARs never block each other.\n        ReentrantLock lock = DOWNLOAD_LOCKS.computeIfAbsent( driverId + \".jar\", k -> new ReentrantLock() );\n        lock.lock();\n        try {\n            Path saveDir = resolveWritableSaveDir();\n            Path savePath = saveDir.resolve( driverId + \".jar\" );\n\n            // Re-check after acquiring the lock: a waiting thread may find the file was already\n            // downloaded by the thread that held the lock before it.\n            if ( Files.isRegularFile( savePath ) ) {\n                log.logBasic( \"JdbcDriverResolver: '\" + driverId + \".jar\" + \"' already downloaded by concurrent thread → \"\n                        + savePath );\n                return savePath.toAbsolutePath().toString();","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/JdbcDriverResolver.java#L226-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$ kettle.sh   # JDBC_DRIVER_SERVICE_URL unset → download impossible\n// after\nexport JDBC_DRIVER_SERVICE_URL=https://driver-service.internal.example.com\nkettle.sh","handlingStrategy":"fallback","validationCode":"String url = System.getenv( \"JDBC_DRIVER_SERVICE_URL\" );\nif ( url == null || url.trim().isEmpty() ) url = System.getProperty( \"JDBC_DRIVER_SERVICE_URL\" );\nboolean downloadAvailable = url != null && !url.trim().isEmpty();","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["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"],"tags":["jdbc","driver","env-var","download"],"backgroundTag":"missing-env-var","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"}