{"record":{"id":"7d9292438452ba5a","repo":"apache/incubator-seata","slug":"class-loader-set-error-you-should-not-use-the-boo","errorCode":null,"errorMessage":"class loader set error, you should not use the Bootstrap classloader","messagePattern":"class loader set error, you should not use the Bootstrap classloader","errorType":"exception","errorClass":"StoreException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java","lineNumber":93,"sourceCode":"        this.dataSource = generate();\n    }\n\n    @Override\n    public DataSource provide() {\n        return this.dataSource;\n    }\n\n    public DataSource generate() {\n        validate();\n        return doGenerate();\n    }\n\n    public void validate() {\n        // valid driver class name\n        String driverClassName = getDriverClassName();\n        ClassLoader loader = getDriverClassLoader();\n        if (null == loader) {\n            throw new StoreException(\"class loader set error, you should not use the Bootstrap classloader\");\n        }\n        try {\n            loader.loadClass(driverClassName);\n        } catch (ClassNotFoundException exx) {\n            String folderPath = System.getProperty(\"loader.path\");\n            if (folderPath == null) {\n                folderPath = System.getProperty(\"java.class.path\");\n            }\n            String driverClassPath = Stream.of(folderPath.split(File.pathSeparator))\n                    .map(File::new)\n                    .filter(File::exists)\n                    .map(file -> file.isFile() ? file.getParentFile() : file)\n                    .filter(Objects::nonNull)\n                    .filter(File::isDirectory)\n                    // Only the MySQL driver needs to be placed in the jdbc folder.\n                    .map(file -> (MYSQL8_DRIVER_CLASS_NAME.equals(driverClassName)\n                                    || MYSQL_DRIVER_CLASS_NAME.equals(driverClassName))\n                            ? new File(file, \"jdbc\")","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/apache/incubator-seata/blob/e01f97c6db397165050caa6764020410c2c8199a/core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java#L75-L111","documentation":"AbstractDataSourceProvider.validate() loads the configured JDBC driver class through getDriverClassLoader(); a null ClassLoader means the class was resolved via the Bootstrap classloader, which cannot see application jars like MySQL/PostgreSQL drivers. Seata refuses with StoreException rather than silently failing later, because store mode db requires an application-level loader to load driver classes.","triggerScenarios":"getDriverClassLoader() returns null — typically when the driver class resolves through the bootstrap/platform classloader (e.g. driver on the JVM's boot classpath, or a custom ClassLoaderStrategy returning null), then validate() throws before any DataSource is generated.","commonSituations":"Seata Server started with the jar on java.ext.dirs or -Xbootclasspath; running inside certain containers/app-server classloader setups; a custom subclass of AbstractDataSourceProvider overriding getDriverClassLoader to return null; JDK 9+ module-path placement putting the driver out of the app loader.","solutions":["Ensure the JDBC driver jar lives on the normal application classpath (lib/ directory of the seata-server distribution or your app's dependencies), not the boot/ext classpath.","If you subclass/extend the provider, implement getDriverClassLoader() to return the class's own loader: `AbstractDataSourceProvider.class.getClassLoader()` or the thread-context classloader.","Start with `java -jar`/standard scripts rather than -Xbootclasspath/-Djava.ext.dirs tricks.","For seata-server, place the driver in the jdbc/ folder as documented so the shipped launcher loads it in the app loader."],"exampleFix":"// before (custom provider)\n@Override\nprotected ClassLoader getDriverClassLoader() {\n    return null; // bootstrap loader -> StoreException\n}\n\n// after\n@Override\nprotected ClassLoader getDriverClassLoader() {\n    return Thread.currentThread().getContextClassLoader();\n}","handlingStrategy":"validation","validationCode":"ClassLoader cl = provider.getDriverClassLoader();\nif (cl == null) {\n    throw new IllegalStateException(\n        \"Driver classloader is null (bootstrap) - put the JDBC driver on the application classpath\");\n}\nprovider.generate();","typeGuard":null,"tryCatchPattern":"try {\n    dataSource = provider.generate();\n} catch (StoreException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Bootstrap classloader\")) {\n        // classpath layout problem: fix launcher/driver location, then restart\n        throw new IllegalStateException(\"Fix driver classpath location\", e);\n    }\n    throw e;\n}","preventionTips":["Run Seata with its standard launcher (bin/seata-server.sh) which wires the correct classloaders.","Put JDBC drivers in the distribution's jdbc//lib folders, never on -Xbootclasspath.","In embedded/custom providers, always return a real ClassLoader from getDriverClassLoader()."],"tags":["jdbc","classloader","datasource","store","server"],"backgroundTag":null,"analyzedSha":"e01f97c6db397165050caa6764020410c2c8199a","analyzedAt":"2026-08-14T10:23:53.097Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}