pentaho/pentaho-kettle · error · KettleDatabaseException
Failed to fetch driver metadata for
Error message
Failed to fetch driver metadata for '{driverId}' — HTTP {status} from {metadataUrl} What it means
The driver-metadata HTTP service responded with a non-200 status. getMetadataFromDriver treats anything other than HTTP 200 as a hard failure and includes the driverId, status code, and requested URL in the message. It wraps problems like 404 (unknown driver), 401/403 (bad bearer token), and 5xx (service down).
Solutions
- Check the status code in the message: 404 => fix driverId or deploy the driver definition; 401/403 => fix the bearer token; 5xx => check service health
- Verify JDBC_DRIVER_SERVICE_URL points at the correct service root (no missing path prefix, no trailing duplication)
- Confirm the driverId exists by calling the same REST endpoint manually (curl) with the same auth header
- Retry if the status is 503/transient and the service is restarting
Example fix
// before
Database.driverMetadata("mysql8x"); // 404: driver not published
// after
Database.driverMetadata("MySQL"); // id that the service actually exposes
// or fix token:
conn.setRequestProperty("Authorization", "Bearer " + validToken); Defensive patterns
Strategy: try-catch
Validate before calling
HttpURLConnection probe = (HttpURLConnection) new URL(baseUrl + "/api/v1/connection-drivers/health").openConnection();
if (probe.getResponseCode() != 200) throw new IllegalStateException("Driver metadata service unhealthy: " + probe.getResponseCode()); Try / catch
try { map = db.driverMetadata(driverId); } catch (KettleDatabaseException e) { if (e.getMessage().matches(".*HTTP \\d+.*")) { int status = parseStatus(e.getMessage()); if (status >= 500 || status == 429) retryWithBackoff(); else log.error("Permanent failure for driverId, status " + status); } else throw e; } Prevention
- Curl the exact metadata endpoint with the same auth header before deploying
- Keep the bearer token fresh and scoped correctly
- Confirm driverIds against the service's published list
- Monitor the metadata service for 5xx rates
When it happens
Trigger: driverMetadata -> getMetadataFromDriver issues GET {base}/api/v1/connection-drivers/{driverId} and the server returns e.g. 404, 401, 403, 500, or 503 instead of 200.
Common situations: Typo'd driverId; metadata service does not know the driver version; expired or missing bearer token (Authorization header rejected); metadata service partially deployed and returning 5xx; a proxy stripping the path.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Failed to fetch driver metadata for
- Carte.Error.NoServerFound
- Client error creating folder
- HTTP Status
- HTTP Status
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/70a4a2eba8664175.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:752
+ "Set the environment variable or system property 'JDBC_DRIVER_SERVICE_URL'." );
}
String metadataUrl = serviceBaseUrl + "/api/v1/connection-drivers/" + driverId;
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL( metadataUrl ).openConnection();
conn.setConnectTimeout( 10_000 );
conn.setReadTimeout( 60_000 );
conn.setRequestMethod( "GET" );
String bearerToken = CmsTokenProvider.getInstance().getToken();
if ( bearerToken != null ) {
conn.setRequestProperty( "Authorization", "Bearer " + bearerToken );
}
int status = conn.getResponseCode();
if ( status != HttpURLConnection.HTTP_OK ) {
throw new KettleDatabaseException(
"Failed to fetch driver metadata for '" + driverId + "' — HTTP " + status + " from " + metadataUrl );
}
try ( java.io.InputStream is = conn.getInputStream() ) {
return new ObjectMapper().readValue( is, Map.class );
}
} catch ( KettleDatabaseException e ) {
throw e;
} catch ( Exception e ) {
throw new KettleDatabaseException(
"Failed to fetch driver metadata for '" + driverId + "' from '" + metadataUrl + "': " + e.getMessage(), e );
} finally {
if ( conn != null ) {
conn.disconnect();
}
}
}
View on GitHub (pinned to f3058517a1)