{"record":{"id":"19eb8c534f10c708","repo":"languagetool-org/languagetool","slug":"user-request-limit-of-per-day-exceeded-try-again","errorCode":null,"errorMessage":"User request limit of  per day exceeded. Try again after midnight UTC.","messagePattern":"User request limit of  per day exceeded\\. Try again after midnight UTC\\.","errorType":"http","errorClass":"TooManyRequestsException","httpStatus":429,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java","lineNumber":179,"sourceCode":"  private String getUserAgent(Map<String, List<String>> httpHeader) {\n    List<String> values = httpHeader.get(\"User-Agent\");\n    if (values == null || values.isEmpty()) {\n      return null;\n    }\n    return values.get(0);\n  }\n\n  static void checkUserLimit(String referer, String userAgent, UserLimits user) {\n    Long maxRequests = user.getRequestsPerDay();\n    if (user.getPremiumUid() != null\n      && maxRequests != null\n      && user.getLimitEnforcementMode() != LimitEnforcementMode.DISABLED) {\n      if (user.getLimitEnforcementMode() == LimitEnforcementMode.PER_DAY) {\n        Long requestCount = DatabaseAccess.getInstance().getUserRequestCount(user.getPremiumUid());\n        //System.out.printf(\"requests for %d: %d / %d%n\", user.getPremiumUid(), requestCount, maxRequests);\n        if (requestCount > maxRequests) {\n          String message = \"limit: \" + maxRequests + \", requests: \" + requestCount + \", enforcement: \" + user.getLimitEnforcementMode().name();\n          throw new TooManyRequestsException(\"User request limit of \" + maxRequests + \" per day exceeded. Try again after midnight UTC.\");\n        }\n      }\n    }\n  }\n\n  void checkLimit(String ipAddress, Map<String, String> parameters, Map<String, List<String>> httpHeader) {\n    int requestsByIp = 0;\n    int requestSizeByIp = 0;\n    int requestsByFingerprint = 0;\n    int requestSizeByFingerprint = 0;\n    // all requests before this date are considered old:\n    Date thresholdDate = new Date(System.currentTimeMillis() - requestLimitPeriodInSeconds * 1000L);\n    String fingerprint = computeFingerprint(httpHeader, parameters);\n    String referer = getReferer(httpHeader);\n    String userAgent = getUserAgent(httpHeader);\n    Long clientId = getClientId(parameters);\n    String user = parameters.get(\"username\");\n    boolean whitelistedUser = user != null && whitelistUsers.contains(user);","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java#L161-L197","documentation":"HTTP 429 error thrown when an authenticated premium user has exceeded their configured maximum number of requests per day. The count comes from the database and the limit is enforced unless the user's enforcement mode is DISABLED.","triggerScenarios":"User with LimitEnforcementMode.PER_DAY and premiumUid whose getUserRequestCount exceeds maxRequests during checkUserLimit.","commonSituations":"CI pipelines or cron jobs burning through daily quotas, shared API credentials used by many services, quota reduced by an admin while usage stayed high, or a retry loop after failures.","solutions":["Wait until after midnight UTC when the daily counter resets","Upgrade the user's daily request quota in the server configuration/database","Distribute traffic across multiple licensed users or add client-side throttling/backoff"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// track local daily usage per user and compare to known quota\nif (usageCounter.today >= userQuotaPerDay) throw new Error('Daily quota would be exceeded; defer requests');","typeGuard":null,"tryCatchPattern":"try {\n  return await check(text);\n} catch (e) {\n  if (e.status === 429 && /per day exceeded/.test(e.message)) {\n    await waitUntilMidnightUTC();\n    return check(text);\n  }\n  throw e;\n}","preventionTips":["Implement client-side daily quotas per API user","Avoid sharing one premium credential across many services","Schedule bulk jobs to spread usage across days"],"tags":["rate-limit","languagetool","http-429"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}