languagetool-org/languagetool · error · BadRequestException
This end point needs a user id
Error message
This end point needs a user id
What it means
LanguageTool's /v2 API endpoint requires a premium user id to resolve account limits. getUserLimits delegates to ServerTools.getUserLimits and, if the resulting UserLimits has no premium UID (no 'username' parameter and/or no configured premium server mapping), it throws BadRequestException. This means the endpoint was called anonymously or with credentials that did not resolve to a premium user.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/ApiV2.java:416
}
private void ensureGetMethod(HttpExchange httpExchange, String url) {
if (!httpExchange.getRequestMethod().equalsIgnoreCase("get")) {
throw new BadRequestException(url + " needs to be called with GET");
}
}
private void ensurePostMethod(HttpExchange httpExchange, String url) {
if (!httpExchange.getRequestMethod().equalsIgnoreCase("post")) {
throw new BadRequestException(url + " needs to be called with POST");
}
}
@NotNull
private UserLimits getUserLimits(Map<String, String> parameters, HTTPServerConfig config) {
UserLimits limits = ServerTools.getUserLimits(parameters, config);
if (limits.getPremiumUid() == null) {
throw new BadRequestException("This end point needs a user id");
}
return limits;
}
private void writeResponse(String fieldName, boolean added, HttpExchange httpExchange) throws IOException {
StringWriter sw = new StringWriter();
try (JsonGenerator g = factory.createGenerator(sw)) {
g.writeStartObject();
g.writeBooleanField(fieldName, added);
g.writeEndObject();
}
sendJson(httpExchange, sw);
}
private void writeListResponse(String fieldName, List<String> words, HttpExchange httpExchange) throws IOException {
StringWriter sw = new StringWriter();
try (JsonGenerator g = factory.createGenerator(sw)) {
g.writeStartObject();View on GitHub (pinned to 2e990059ce)
Solutions
- Add the 'username' (and 'apiKey' if required) parameters to the request.
- Verify the account is a premium account registered on the server.
- If self-hosting, ensure HTTPServerConfig premium settings are set so usernames resolve to a premium UID.
- Check the endpoint actually requires user limits; use an endpoint that supports anonymous access otherwise.
Example fix
// before curl 'https://api.languagetool.org/v2/limits' // after curl -d 'username=myuser&apiKey=MYKEY' 'https://api.languagetool.org/v2/limits'
Defensive patterns
Strategy: validation
Validate before calling
if (!params.has('username') || !params.get('username')) {
throw new Error('This endpoint requires a premium username parameter');
} Type guard
function hasPremiumUser(params) {
return typeof params.username === 'string' && params.username.trim().length > 0;
} Try / catch
try {
const res = await fetch(url, { method: 'POST', body: form });
if (res.status === 400) throw new Error(await res.text());
} catch (e) {
console.error('User limits request rejected:', e.message);
} Prevention
- Always include username/apiKey for premium endpoints.
- Verify account premium status before calling limits endpoints.
- Centralize auth parameter injection in your API client.
When it happens
Trigger: Calling a limits-related API v2 endpoint without a 'username' parameter, with an empty username, or with a username that does not map to a premium UID given the server's HTTPServerConfig.
Common situations: Scripts testing the public API without an account; self-hosted servers hit with endpoints that assume premium setup; clients that dropped the username field after a parameter rename.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Only either 'text' or 'markup' are supported in an object in
- 'text' cannot be used with 'interpretAs' (only 'markup' can)
- Only 'text' and 'markup' are supported in 'annotation' list:
- apiKey AND password was set, set only apiKey
- With 'username' set, you also need to specify 'apiKey'
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/baec4de337015b2e.
Report an issue: GitHub.