alibaba/druid · error · IllegalArgumentException

{className}

Error message

{className}

What it means

DruidAbstractDataSource.setStatLoggerClassName reflectively loads, instantiates, and casts a class to DruidDataSourceStatLogger. Any failure (ClassNotFoundException, InstantiationException, IllegalAccessException, ClassCastException, or a constructor-thrown exception) is wrapped as IllegalArgumentException(className, e) - note the message is just the class name and the real cause is in the exception's cause.

Solutions

  1. Confirm the class is on the classpath and implements com.alibaba.druid.stat.DruidDataSourceStatLogger.
  2. Ensure a public no-arg constructor exists and the class is concrete/public.
  3. Prefer setStatLogger(new MyStatLogger()) to get a compile-time type check instead of reflective loading.
  4. Read IllegalArgumentException.getCause() to identify ClassNotFoundException vs ClassCastException vs InstantiationException.

Example fix

// before
// ds.setStatLoggerClassName("com.example.MyStatLogger"); // reflective, runtime-only

// after
// ds.setStatLogger(new com.example.MyStatLogger()); // compile-time checked
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> c = Class.forName(className);
if (!com.alibaba.druid.stat.DruidDataSourceStatLogger.class.isAssignableFrom(c))
    throw new IllegalStateException(className + " is not a DruidDataSourceStatLogger");
com.alibaba.druid.stat.DruidDataSourceStatLogger probe =
    (com.alibaba.druid.stat.DruidDataSourceStatLogger) c.newInstance();

Type guard

static boolean isValidStatLoggerClass(String name) {
    try {
        Class<?> c = Class.forName(name);
        return com.alibaba.druid.stat.DruidDataSourceStatLogger.class.isAssignableFrom(c)
            && !java.lang.reflect.Modifier.isAbstract(c.getModifiers());
    } catch (Throwable t) { return false; }
}

Try / catch

try {
    ds.setStatLoggerClassName(className);
} catch (IllegalArgumentException e) {
    // e.getMessage() == className; e.getCause() tells you which: CNFE/CCE/IE/IAE
    // prefer ds.setStatLogger(new MyStatLogger()) instead
    throw e;
}

Prevention

When it happens

Trigger: Calling setStatLoggerClassName("foo.Bar") where Bar is not on the classpath, is abstract/inaccessible, does not implement DruidDataSourceStatLogger, or its constructor throws.

Common situations: Typo in the stat logger class name; the logger class lives in a JAR not on the datasource's classloader; providing a class that implements a different Druid version's DruidDataSourceStatLogger interface.

Related errors


AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14). Data as JSON: /api/errors/eddfbf56e63c6a97. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java:343

        return keepConnectionUnderlyingTransactionIsolation;
    }

    public void setKeepConnectionUnderlyingTransactionIsolation(boolean keepConnectionUnderlyingTransactionIsolation) {
        this.keepConnectionUnderlyingTransactionIsolation = keepConnectionUnderlyingTransactionIsolation;
    }

    public DruidDataSourceStatLogger getStatLogger() {
        return statLogger;
    }

    public void setStatLoggerClassName(String className) {
        Class<?> clazz;
        try {
            clazz = Class.forName(className);
            DruidDataSourceStatLogger statLogger = (DruidDataSourceStatLogger) clazz.newInstance();
            this.setStatLogger(statLogger);
        } catch (Exception e) {
            throw new IllegalArgumentException(className, e);
        }
    }

    public void setStatLogger(DruidDataSourceStatLogger statLogger) {
        this.statLogger = statLogger;
    }

    public long getTimeBetweenLogStatsMillis() {
        return timeBetweenLogStatsMillis;
    }

    public void setTimeBetweenLogStatsMillis(long timeBetweenLogStatsMillis) {
        this.timeBetweenLogStatsMillis = timeBetweenLogStatsMillis;
    }

    public boolean isOracle() {
        return isOracle;
    }

View on GitHub (pinned to fa8dc99126)