languagetool-org/languagetool · error · AuthException
This is the endpoint for the basic version of LanguageTool.
Error message
This is the endpoint for the basic version of LanguageTool. When using 'username' and 'apiKey' to access the premium version, use api.languagetoolplus.com instead.
What it means
When sqlSessionFactory is null, the open-source implementation has no database configured, so getUserId throws AuthException telling the caller that this is the basic LanguageTool endpoint and username/apiKey (premium) auth belongs on api.languagetoolplus.com. It is a routing/configuration error: credentials were provided to a server that cannot process them.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/DatabaseAccessOpenSource.java:212
Date now = new Date();
map.put("created_at", now);
map.put("updated_at", now);
int affectedRows = session.insert("org.languagetool.server.UserDictMapper.addWord", map);
logger.info("Added '" + word + "' for user " + userId + " to list of ignored words, affectedRows: " + affectedRows);
return affectedRows == 1;
}
}
}
Long getUserId(String username, String apiKey) {
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException("username must be set");
}
if (apiKey == null || apiKey.trim().isEmpty()) {
throw new IllegalArgumentException("apiKey must be set");
}
if (sqlSessionFactory == null) {
throw new AuthException("This is the endpoint for the basic version of LanguageTool. " +
"When using 'username' and 'apiKey' to access the premium version, use api.languagetoolplus.com instead.");
}
try {
Long value = dbLoggingCache.get(String.format("user_%s_%s", username, apiKey), () -> {
try (SqlSession session = sqlSessionFactory.openSession()) {
Map<Object, Object> map = new HashMap<>();
map.put("username", username);
map.put("apiKey", apiKey);
Long id = session.selectOne("org.languagetool.server.UserDictMapper.getUserIdByApiKey", map);
if (id == null) {
return -1L;
}
return id;
}
});
if (value == -1) {
throw new IllegalArgumentException("No user found for given username '" + username + "' and given api key");
} else {View on GitHub (pinned to 2e990059ce)
Solutions
- If you have a premium subscription, change the client endpoint to https://api.languagetoolplus.com.
- If self-hosting with your own users, start the server with database configuration so sqlSessionFactory is initialized (premium setup required for the bundled DB support).
- Remove username/apiKey from the request when using the basic open-source server (use anonymous or OSS-supported auth).
Example fix
// before
POST http://localhost:8081/v2/check { "username":"bob", "apiKey":"k" } // AuthException
// after
POST https://api.languagetoolplus.com/v2/check { "username":"bob", "apiKey":"k" }
// or, on the basic server, omit username/apiKey entirely Defensive patterns
Strategy: validation
Validate before calling
if (usesUsernameApiKeyAuth && !isPremiumEndpoint(baseUrl)) {
throw new IllegalArgumentException("username/apiKey only valid on api.languagetoolplus.com or a DB-configured server");
} Type guard
boolean isPremiumEndpoint(String url) { return url != null && url.contains("languagetoolplus.com"); } Try / catch
try {
response = api.check(text, username, apiKey);
} catch (AuthException e) {
// retry without credentials or redirect to premium endpoint
} Prevention
- Match auth scheme to server edition: credentials only for premium or DB-configured servers.
- Read the server startup config to know whether database auth is enabled.
- Route premium credentials to api.languagetoolplus.com in client configuration.
When it happens
Trigger: Sending username + apiKey authentication to an open-source languagetool-server that was started WITHOUT database configuration (no MyBatis/sqlSessionFactory), i.e. any request hitting getUserId on a basic self-hosted instance.
Common situations: Self-hosting LanguageTool and passing premium credentials (username/apiKey) that only work on the paid service; a server started without --database* config options receiving premium-style auth.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- This server does not support username/password
- username must be set
- apiKey must be set
- No user found for given username '' and given api key
- WrongParameterNumberException
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/6bf2d5391d4bbfd5.
Report an issue: GitHub.