{"record":{"id":"baec4de337015b2e","repo":"languagetool-org/languagetool","slug":"this-end-point-needs-a-user-id","errorCode":null,"errorMessage":"This end point needs a user id","messagePattern":"This end point needs a user id","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/ApiV2.java","lineNumber":416,"sourceCode":"  }\n\n  private void ensureGetMethod(HttpExchange httpExchange, String url) {\n    if (!httpExchange.getRequestMethod().equalsIgnoreCase(\"get\")) {\n      throw new BadRequestException(url + \" needs to be called with GET\");\n    }\n  }\n  \n  private void ensurePostMethod(HttpExchange httpExchange, String url) {\n    if (!httpExchange.getRequestMethod().equalsIgnoreCase(\"post\")) {\n      throw new BadRequestException(url + \" needs to be called with POST\");\n    }\n  }\n\n  @NotNull\n  private UserLimits getUserLimits(Map<String, String> parameters, HTTPServerConfig config) {\n    UserLimits limits = ServerTools.getUserLimits(parameters, config);\n    if (limits.getPremiumUid() == null) {\n      throw new BadRequestException(\"This end point needs a user id\");\n    }\n    return limits;\n  }\n\n  private void writeResponse(String fieldName, boolean added, HttpExchange httpExchange) throws IOException {\n    StringWriter sw = new StringWriter();\n    try (JsonGenerator g = factory.createGenerator(sw)) {\n      g.writeStartObject();\n      g.writeBooleanField(fieldName, added);\n      g.writeEndObject();\n    }\n    sendJson(httpExchange, sw);\n  }\n  \n  private void writeListResponse(String fieldName, List<String> words, HttpExchange httpExchange) throws IOException {\n    StringWriter sw = new StringWriter();\n    try (JsonGenerator g = factory.createGenerator(sw)) {\n      g.writeStartObject();","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/ApiV2.java#L398-L434","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncurl 'https://api.languagetool.org/v2/limits'\n// after\ncurl -d 'username=myuser&apiKey=MYKEY' 'https://api.languagetool.org/v2/limits'","handlingStrategy":"validation","validationCode":"if (!params.has('username') || !params.get('username')) {\n  throw new Error('This endpoint requires a premium username parameter');\n}","typeGuard":"function hasPremiumUser(params) {\n  return typeof params.username === 'string' && params.username.trim().length > 0;\n}","tryCatchPattern":"try {\n  const res = await fetch(url, { method: 'POST', body: form });\n  if (res.status === 400) throw new Error(await res.text());\n} catch (e) {\n  console.error('User limits request rejected:', e.message);\n}","preventionTips":["Always include username/apiKey for premium endpoints.","Verify account premium status before calling limits endpoints.","Centralize auth parameter injection in your API client."],"tags":["http","api","languagetool","bad-request"],"backgroundTag":"missing-required-argument","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}