languagetool-org/languagetool · error · IllegalArgumentException

dbLogging can only be true if dbDriver, dbUrl, dbUsername…

Error message

dbLogging can only be true if dbDriver, dbUrl, dbUsername, and dbPassword are all set

What it means

When 'dbLogging=true' the server logs rule matches to a database, which requires complete JDBC connection settings: dbDriver, dbUrl, dbUsername, and dbPassword. If any of these is null, HTTPServerConfig throws this IllegalArgumentException because logging to the DB would fail.

Solutions

  1. Set all four properties: dbDriver (e.g. com.mysql.cj.jdbc.Driver), dbUrl, dbUsername, dbPassword
  2. Inject the missing values at deploy time via environment-variable substitution in the properties template
  3. Set 'dbLogging=false' if database logging is not actually needed

Example fix

// before (server.properties)
dbLogging=true
dbUrl=jdbc:mysql://localhost/ltlogs

// after (server.properties)
dbLogging=true
dbDriver=com.mysql.cj.jdbc.Driver
dbUrl=jdbc:mysql://localhost/ltlogs
dbUsername=ltuser
dbPassword=secret
Defensive patterns

Strategy: validation

Validate before calling

if (Boolean.parseBoolean(props.getProperty("dbLogging", "false"))) {
    for (String k : new String[]{"dbDriver", "dbUrl", "dbUsername", "dbPassword"}) {
        if (props.getProperty(k) == null) throw new IllegalStateException("dbLogging=true requires " + k);
    }
}

Try / catch

try {
    serverConfig = new HTTPServerConfig(props);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("dbLogging can only be true")) {
        log.error("Incomplete DB config; check dbDriver/dbUrl/dbUsername/dbPassword");
    }
    throw e;
}

Prevention

When it happens

Trigger: Server properties file contains 'dbLogging=true' but is missing one or more of dbDriver, dbUrl, dbUsername, or dbPassword.

Common situations: Credentials omitted from the config for security but not injected via environment/template; partial config copied from another environment; dbDriver/dbUrl forgotten while only user/password set.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/23190562b293de00. Report an issue: GitHub.

Appendix: source

Thrown at languagetool-server/src/main/java/org/languagetool/server/HTTPServerConfig.java:462

        gracefulDatabaseFailure = Boolean.parseBoolean(getOptionalProperty(props, "gracefulDatabaseFailure", "false").trim());
        dbDriver = getOptionalProperty(props, "dbDriver", null);
        dbUrl = getOptionalProperty(props, "dbUrl", null);
        dbUsername = getOptionalProperty(props, "dbUsername", null);
        dbPassword = getOptionalProperty(props, "dbPassword", null);
        dbTimeoutSeconds = Integer.parseInt(getOptionalProperty(props, "dbTimeoutSeconds", "10"));
        dbMaxConnections = Integer.parseInt(getOptionalProperty(props, "dbMaxConnections", "10"));
        databaseErrorRateThreshold = Integer.parseInt(getOptionalProperty(props, "dbErrorRateThreshold", "50"));
        databaseTimeoutRateThreshold = Integer.parseInt(getOptionalProperty(props, "dbTimeoutRateThreshold", "100"));
        databaseDownIntervalSeconds = Integer.parseInt(getOptionalProperty(props, "dbDownIntervalSeconds", "10"));
        dbLogging = Boolean.valueOf(getOptionalProperty(props, "dbLogging", "false").trim());
        passwortLoginAccessListPath = getOptionalProperty(props, "passwortLoginAccessListPath", "");
        prometheusMonitoring = Boolean.valueOf(getOptionalProperty(props, "prometheusMonitoring", "false").trim());
        prometheusPort = Integer.parseInt(getOptionalProperty(props, "prometheusPort", "9301"));
        skipLoggingRuleMatches = Boolean.valueOf(getOptionalProperty(props, "skipLoggingRuleMatches", "false").trim());
        skipLoggingChecks = Boolean.valueOf(getOptionalProperty(props, "skipLoggingChecks", "false").trim());
        if (dbLogging && (dbDriver == null || dbUrl == null || dbUsername == null || dbPassword == null)) {
          throw new IllegalArgumentException("dbLogging can only be true if dbDriver, dbUrl, dbUsername, and dbPassword are all set");
        }
        slowRuleLoggingThreshold = Integer.valueOf(getOptionalProperty(props, "slowRuleLoggingThreshold", "-1"));
        disabledRuleIds = Arrays.asList(getOptionalProperty(props, "disabledRuleIds", "").split(",\\s*"));
        localApiMode = Boolean.parseBoolean(getOptionalProperty(props, "localApiMode", "false"));
        motherTongue = getOptionalProperty(props, "motherTongue", "en-US");
        String preferredLanguages = getOptionalProperty(props, "preferredLanguages", "").replace(" ", "");
        if (!preferredLanguages.equals("")) {
          this.preferredLanguages = Arrays.asList(preferredLanguages.split(","));
        }
        dictLimitUser = Integer.valueOf(getOptionalProperty(props, "dictLimitUser", "0"));
        dictLimitTeam = Integer.valueOf(getOptionalProperty(props, "dictLimitTeam", "0"));
        styleGuideLimitUser = Integer.valueOf(getOptionalProperty(props, "styleGuideLimitUser", "0"));
        styleGuideLimitTeam = Integer.valueOf(getOptionalProperty(props, "styleGuideLimitTeam", "0"));
        requestLimitAccessToken = getOptionalProperty(props, "requestLimitAccessToken", null);
        jwtSecret = getOptionalProperty(props, "jwtSecret", null);
        externalRolloutServiceUrl = getOptionalProperty(props, "externalRolloutServiceUrl", null);
        externalRolloutServiceApiKey = getOptionalProperty(props, "externalRolloutServiceApiKey", null);

View on GitHub (pinned to 2e990059ce)