languagetool-org/languagetool · error · BadRequestException
apiKey AND password was set, set only apiKey
Error message
apiKey AND password was set, set only apiKey
What it means
ServerTools.getUserLimits validates authentication parameters for /v2/check. Passing both apiKey and password with a username is ambiguous (two credential schemes), so it throws BadRequestException (HTTP 400) telling you to send only apiKey.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/ServerTools.java:145
static void setCommonHeaders(HttpExchange httpExchange, String contentType, String allowOriginUrl) {
httpExchange.getResponseHeaders().set("Content-Type", contentType);
setAllowOrigin(httpExchange, allowOriginUrl);
}
static void setAllowOrigin(HttpExchange httpExchange, String allowOriginUrl) {
if (allowOriginUrl != null) {
httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", allowOriginUrl);
}
}
static UserLimits getUserLimits(Map<String, String> params, HTTPServerConfig config) {
return getUserLimits(params, config, null);
}
static UserLimits getUserLimits(Map<String, String> params, HTTPServerConfig config, String authHeader) {
if (params.get("username") != null) {
if (params.get("apiKey") != null && params.get("password") != null) {
throw new BadRequestException("apiKey AND password was set, set only apiKey");
}
if (params.get("apiKey") != null) {
return UserLimits.getLimitsByApiKey(config, params.get("username"), params.get("apiKey"));
} else if (params.get("password") != null) {
return UserLimits.getLimitsFromUserAccount(config, params.get("username"), params.get("password"));
} else if (params.get("tokenV2") != null) {
if (authHeader != null) {
return UserLimits.getLimitsWithJwtToken(config, authHeader, params.get("username"), params.get("tokenV2"));
}
return UserLimits.getLimitsByAddonToken(config, params.get("username"), params.get("tokenV2"));
} else {
throw new BadRequestException("With 'username' set, you also need to specify 'apiKey'");
}
} else {
if (params.get("apiKey") != null) {
throw new BadRequestException("apiKey was set, but username was not: " + params.get("apiKey"));
}
if (params.get("password") != null) {View on GitHub (pinned to 2e990059ce)
Solutions
- Remove the password parameter and keep username + apiKey
- Remove apiKey and keep username + password if you intentionally use password auth (legacy)
- Search your client code/config for where both params are injected and make them mutually exclusive
Example fix
// before
params.put("username", user); params.put("apiKey", key); params.put("password", pwd);
// after
params.put("username", user); params.put("apiKey", key); // drop password Defensive patterns
Strategy: validation
Validate before calling
function validateAuthParams(params) {
if (params.username && params.apiKey && params.password) {
throw new Error('Send only apiKey (or only password), not both');
}
} Try / catch
try {
return await lt.check(params);
} catch (e) {
if (e.status === 400 && /apiKey AND password/.test(e.message)) {
delete params.password; return await lt.check(params);
}
throw e;
} Prevention
- Make apiKey and password mutually exclusive in your client config layer
- Remove legacy password params after migrating to API keys
- Write a unit test asserting the request params contain exactly one credential scheme
When it happens
Trigger: Calling /v2/check with params username=X, apiKey=Y, AND password=Z — any request containing all three parameters.
Common situations: Migrating from old username/password auth to API keys and leaving the old password param in the client config; template/query builders that always append both fields; copy-pasted example code including both.
Understand the failure class
Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.
Related errors
- With 'username' set, you also need to specify 'apiKey'
- apiKey was set, but username was not: {apiKey}
- password was set, but username was not
- Expected Basic Authentication
- This end point needs a user id
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/21ab2cf20c23cda5.
Report an issue: GitHub.