{"record":{"id":"0620d5408eaf5c3c","repo":"languagetool-org/languagetool","slug":"client-request-size-limit-of-bytes-per-seconds-e-0620d5","errorCode":null,"errorMessage":"Client request size limit of  bytes per  seconds exceeded","messagePattern":"Client request size limit of  bytes per  seconds exceeded","errorType":"http","errorClass":"TooManyRequestsException","httpStatus":429,"severity":"warning","filePath":"languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java","lineNumber":240,"sourceCode":"          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) {\n            String msg = \"limit in Mode.TEXTLEVEL_ONLY: \" + requestLimitInBytes + \" / \" + requestLimitPeriodInSeconds + \", request size: \"  + requestSizeByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n            throw new TooManyRequestsException(\"Client request size limit of \" + requestLimitInBytes + \" bytes per \" +\n              requestLimitPeriodInSeconds + \" seconds exceeded in text-level checks\");\n          }\n          if (requestLimitInBytes > 0 && requestSizeByIp > ipRequestLimitInBytes) {\n            String msg = \"limit in Mode.TEXTLEVEL_ONLY: \" + ipRequestLimitInBytes + \" / \" + requestLimitPeriodInSeconds + \", request size: \"  + requestSizeByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n            throw new TooManyRequestsException(\"IP request size limit of \" + ipRequestLimitInBytes + \" bytes per \" +\n              requestLimitPeriodInSeconds + \" seconds exceeded in text-level checks\");\n          }\n        } else {\n          if (ipFingerprintFactor > 0 && requestLimitInBytes > 0 && requestSizeByFingerprint > requestLimitInBytes) {\n            String msg = \"limit: \" + requestLimitInBytes + \" / \" + requestLimitPeriodInSeconds + \", request size: \"  + requestSizeByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n            throw new TooManyRequestsException(\"Client request size limit of \" + requestLimitInBytes + \" bytes per \" +\n              requestLimitPeriodInSeconds + \" seconds exceeded\");\n          }\n          if (requestLimitInBytes > 0 && requestSizeByIp > ipRequestLimitInBytes) {\n            String msg = \"limit: \" + ipRequestLimitInBytes + \" / \" + requestLimitPeriodInSeconds + \", request size: \"  + requestSizeByIp + \", ip: \" + ipAddress + \", fingerprint: \" + fingerprint;\n            throw new TooManyRequestsException(\"IP request size limit of \" + ipRequestLimitInBytes + \" bytes per \" +\n              requestLimitPeriodInSeconds + \" seconds exceeded\");\n          }\n        }\n      }\n    }\n  }\n  \n  protected static class RequestEvent {\n\n    private final String ip;\n    private final Date date;\n    private final int sizeInBytes;\n    private final String fingerprint;","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java#L222-L258","documentation":"Outside TEXTLEVEL_ONLY mode, RequestLimiter enforces a per-fingerprint request-size quota on all checks. When bytes sent under one fingerprint exceed requestLimitInBytes within requestLimitPeriodInSeconds, checkLimit throws TooManyRequestsException (HTTP 429). This is the general (non-text-level-only) client size cap.","triggerScenarios":"POSTing to /v2/check (mode=all/allButTextLevelOnly/unset) when the fingerprint-weighted cumulative request size exceeds requestLimitInBytes within requestLimitPeriodInSeconds, with ipFingerprintFactor > 0 and requestLimitInBytes > 0.","commonSituations":"Free/public API users submitting very large texts; apps checking whole documents per keystroke; shared fingerprint (same browser/params) across many requests; low requestLimitInBytes set in server config.","solutions":["Wait for the limit period to reset, then send fewer/smaller requests","Split large texts into chunks below the per-window size budget and pace requests","Authenticate with Premium credentials (username/apiKey) for higher limits","If operating the server, increase requestLimitInBytes (e.g. --limitRequestSizeInBytes) or adjust ipFingerprintFactor/requestLimitPeriodInSeconds","Avoid reusing an identical fingerprint-heavy request pattern; vary/reduce what is sent or use authenticated access"],"exampleFix":"// before\nresp = check(mode=\"all\", text=wholeBook);\n// after\nchunks = split(wholeBook, 20000);\nfor c in chunks: checkWithBackoff(mode=\"all\", text=c);","handlingStrategy":"retry","validationCode":"if (new Blob([text]).size > MAX_CHUNK_BYTES) text = chunk(text, MAX_CHUNK_BYTES);","typeGuard":null,"tryCatchPattern":"try {\n  return await check(text, mode);\n} catch (e) {\n  if (e.status === 429) { await exponentialBackoff(); return check(text, mode); }\n  throw e;\n}","preventionTips":["Split large payloads to stay under requestLimitInBytes per window","Pace requests rather than sending bursts that share one fingerprint","Prefer authenticated limits for production workloads","Self-host with raised size limits if your documents are large"],"tags":["rate-limit","http","http-429","languagetool"],"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-14T05:17:10.506Z"}