{"record":{"id":"935508ab09da4029","repo":"languagetool-org/languagetool","slug":"whitelist-request-limit-of-requests-per-seconds","errorCode":null,"errorMessage":"Whitelist request limit of  requests per  seconds exceeded","messagePattern":"Whitelist request limit of  requests per  seconds exceeded","errorType":"http","errorClass":"TooManyRequestsException","httpStatus":429,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java","lineNumber":209,"sourceCode":"    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);\n    for (RequestEvent event : requestEvents) {\n      if (event.ip.equals(ipAddress) && event.date.after(thresholdDate)) {\n        // text level rules cause much less load, so count them accordingly\n        float modeFactor = event.mode == JLanguageTool.Mode.TEXTLEVEL_ONLY ? 0.1f : 1f;\n        requestsByIp++;\n        requestSizeByIp += event.getSizeInBytes() * modeFactor;\n        if (whitelistedUser) {\n          if (whitelistLimit <= 0 || requestsByIp < whitelistLimit) {\n            continue;\n          } else {\n            String msg = \"limit: \" + ipRequestLimit + \" / \" + requestLimitPeriodInSeconds + \", requests: \"  + requestsByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n            throw new TooManyRequestsException(\"Whitelist request limit of \" + whitelistLimit + \" requests per \" +\n              requestLimitPeriodInSeconds + \" seconds exceeded\");\n          }\n        }\n        if (event.fingerprint.equals(fingerprint)) {\n          requestsByFingerprint++;\n          requestSizeByFingerprint += event.getSizeInBytes() * modeFactor;\n        }\n        if (ipFingerprintFactor > 0 && requestLimit > 0 && requestsByFingerprint > requestLimit) {\n          String msg = \"limit: \" + requestLimit + \" / \" + requestLimitPeriodInSeconds + \", requests: \"  + requestsByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n          throw new TooManyRequestsException(\"Client request limit of \" + requestLimit + \" requests per \" +\n            requestLimitPeriodInSeconds + \" seconds exceeded\"); }\n        if (requestLimit > 0 && requestsByIp > ipRequestLimit) {\n          String msg = \"limit: \" + ipRequestLimit + \" / \" + requestLimitPeriodInSeconds + \", requests: \"  + requestsByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n          throw new TooManyRequestsException(\"IP request limit of \" + ipRequestLimit + \" requests per \" +\n            requestLimitPeriodInSeconds + \" seconds exceeded\");\n        }\n        if (event.mode == JLanguageTool.Mode.TEXTLEVEL_ONLY) {\n          if (ipFingerprintFactor > 0 && requestLimitInBytes > 0 && requestSizeByFingerprint > requestLimitInBytes) {","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java#L191-L227","documentation":"HTTP 429 error thrown when an IP on the whitelist exceeds its special per-period request rate. Whitelisted IPs get their own (usually higher) limit; when requests from that IP within requestLimitPeriodInSeconds exceed whitelistLimit, the request is rejected.","triggerScenarios":"checkLimit called via checkAccess while whitelistedUser is true and requestsByIp >= whitelistLimit within the sliding period.","commonSituations":"Whitelisted office/VPN IP shared by many users exhausting its quota, monitoring/health checks hitting the API too frequently from an allowlisted host, or whitelistLimit misconfigured to a very low value.","solutions":["Increase the whitelistLimit in the server's rate-limit configuration","Spread load: have clients behind the whitelisted IP use separate API keys or back off","Reduce polling frequency of automated clients and add client-side rate limiting"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const MIN_INTERVAL_MS = (periodSeconds * 1000) / whitelistLimit;\nlet last = 0;\nasync function throttle() {\n  const wait = last + MIN_INTERVAL_MS - Date.now();\n  if (wait > 0) await new Promise(r => setTimeout(r, wait));\n  last = Date.now();\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await check(text);\n} catch (e) {\n  if (e.status === 429 && /Whitelist request limit/.test(e.message)) {\n    await sleep(periodSeconds * 1000);\n    return check(text);\n  }\n  throw e;\n}","preventionTips":["Throttle all clients sharing a whitelisted IP","Lower health-check/polling frequency","Review whitelistLimit sizing against real team load"],"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"}