t8y2/dbx · error · IOException

Custom H2 JDBC JAR does not exist: " + path

Error message

Custom H2 JDBC JAR does not exist: " + path

What it means

loadExternal validates each configured JAR path: it resolves to an absolute normalized Path and requires it to be a regular file. A configured path that does not exist (or is a directory) causes this IOException so the loader never builds a class loader over bogus URLs.

Source

Thrown at agents/drivers/h2/src/main/java/com/dbx/agent/h2/H2DriverLoader.java:51

        } catch (Exception error) {
            closeAfterFailure(classLoader, error);
            throw error;
        } catch (LinkageError error) {
            closeAfterFailure(classLoader, error);
            throw error;
        }
    }

    static LoadedDriver loadExternal(List<String> driverPaths, String driverClass) throws Exception {
        if (driverPaths == null || driverPaths.isEmpty()) {
            throw new IllegalArgumentException("Custom H2 driver profile requires at least one JDBC JAR path");
        }
        List<URL> urls = new ArrayList<>();
        List<String> identities = new ArrayList<>();
        for (String driverPath : driverPaths) {
            Path path = Path.of(driverPath).toAbsolutePath().normalize();
            if (!Files.isRegularFile(path)) {
                throw new IOException("Custom H2 JDBC JAR does not exist: " + path);
            }
            urls.add(path.toUri().toURL());
            identities.add(path + ":" + sha256(path));
        }
        String effectiveDriverClass = driverClass == null || driverClass.isBlank() ? "org.h2.Driver" : driverClass.trim();
        URLClassLoader classLoader = new URLClassLoader(
            urls.toArray(new URL[0]),
            H2DriverLoader.class.getClassLoader()
        );
        try {
            Driver driver = (Driver) Class.forName(effectiveDriverClass, true, classLoader).getDeclaredConstructor().newInstance();
            return new LoadedDriver(H2DriverVersion.CUSTOM, effectiveDriverClass + "|" + String.join("|", identities), driver, classLoader);
        } catch (Exception error) {
            closeAfterFailure(classLoader, error);
            throw error;
        } catch (LinkageError error) {
            closeAfterFailure(classLoader, error);
            throw error;

View on GitHub (pinned to c0390bff16)

Solutions

  1. Correct the configured path to point at an existing JDBC JAR file (verify with ls / Files.exists)
  2. Copy the H2 JAR to the expected location before starting the agent
  3. Use an absolute path in configuration so it does not depend on the process working directory

Example fix

// before
H2DriverLoader.loadExternal(List.of("/opt/drivers/h2.jar"), null); // file deleted
// after
H2DriverLoader.loadExternal(List.of("/opt/drivers/h2-2.2.224.jar"), null); // file present
Defensive patterns

Strategy: validation

Validate before calling

List<String> valid = driverPaths.stream()
    .filter(p -> Files.isRegularFile(Path.of(p).toAbsolutePath().normalize()))
    .toList();
if (valid.size() != driverPaths.size()) throw new IllegalStateException("missing JAR(s)");

Try / catch

try {
    return H2DriverLoader.loadExternal(driverPaths, driverClass);
} catch (IOException e) {
    logger.error("Configured H2 JAR missing: {}", e.getMessage());
    throw new ConfigurationException(e);
}

Prevention

When it happens

Trigger: Calling loadExternal with a driverPaths entry pointing to a nonexistent file, a deleted/moved JAR, or a directory path.

Common situations: JAR deleted by cleanup job or upgrade script; relative path resolved from a different working directory; typo in the configured path; JAR is on a not-yet-mounted volume.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/645c5b9ea77ab269. Report an issue: GitHub.