languagetool-org/languagetool · warning · TooManyRequestsException
IP request size limit of bytes per seconds exceeded in…
Error message
IP request size limit of bytes per seconds exceeded in text-level checks
What it means
RequestLimiter enforces a per-IP request-size quota in Mode.TEXTLEVEL_ONLY. When the total bytes of requests from one IP address exceed ipRequestLimitInBytes within requestLimitPeriodInSeconds, checkLimit throws TooManyRequestsException (HTTP 429). This limits aggregate bandwidth per client IP regardless of fingerprint.
Solutions
- Wait for requestLimitPeriodInSeconds to pass, then resume with reduced volume
- Add client-side throttling/backoff: track bytes sent and cap below ipRequestLimitInBytes per window
- Use an authenticated Premium account with higher per-IP limits
- If you administer the server, raise the IP size limit (ipRequestLimitInBytes) in HTTPServerConfig/launch options
- Move the workload to a different IP or distribute requests across allowed clients
Example fix
// before: unbounded loop
for (doc : docs) client.check(doc, Mode.TEXTLEVEL_ONLY);
// after: rate-aware loop
long sent = 0; long windowStart = now();
for (doc : docs) {
if (now()-windowStart > period) { sent = 0; windowStart = now(); }
if (sent + doc.length() > ipLimitBytes) sleep(windowStart + period - now());
client.check(doc, Mode.TEXTLEVEL_ONLY); sent += doc.length();
} Defensive patterns
Strategy: retry
Validate before calling
function canSend(bytes) { return bytesSentFromThisIpInWindow + bytes <= IP_LIMIT_BYTES; } Try / catch
try {
const res = await api.check(text);
} catch (e) {
if (e.response && e.response.status === 429) { await sleep(periodMs); return api.check(text); }
throw e;
} Prevention
- Throttle request volume per IP; serialize jobs instead of parallel bursts
- Distribute workload across allowed IPs or use authenticated access
- Back off on 429 instead of retrying immediately
- Monitor usage and alert before hitting the per-window byte cap
When it happens
Trigger: POSTing to /v2/check with mode=textLevelOnly where cumulative request bytes from the client IP exceed ipRequestLimitInBytes within requestLimitPeriodInSeconds (and requestLimitInBytes > 0).
Common situations: Automated scripts or CI jobs behind one IP sending many large requests; multiple users behind a NAT/proxy sharing the quota; server configured with a tight IP size limit (ipRequestLimitInBytes); rapid retry loops amplifying usage.
Related errors
- Client request size limit of bytes per seconds exceeded…
- Client request size limit of bytes per seconds exceeded
- IP request size limit of bytes per seconds exceeded
- Client request limit of requests per seconds exceeded
- IP request limit of requests per seconds exceeded
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/6cc5098e2efeec57.
Report an issue: GitHub.
Appendix: source
Thrown at languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java:234
}
if (ipFingerprintFactor > 0 && requestLimit > 0 && requestsByFingerprint > requestLimit) {
String msg = "limit: " + requestLimit + " / " + requestLimitPeriodInSeconds + ", requests: " + requestsByIp + ", ip: " + ipAddress + ", fingerprint: " + fingerprint;
throw new TooManyRequestsException("Client request limit of " + requestLimit + " requests per " +
requestLimitPeriodInSeconds + " seconds exceeded"); }
if (requestLimit > 0 && requestsByIp > ipRequestLimit) {
String msg = "limit: " + ipRequestLimit + " / " + requestLimitPeriodInSeconds + ", requests: " + requestsByIp + ", ip: " + ipAddress + ", fingerprint: " + fingerprint;
throw new TooManyRequestsException("IP request limit of " + ipRequestLimit + " requests per " +
requestLimitPeriodInSeconds + " seconds exceeded");
}
if (event.mode == JLanguageTool.Mode.TEXTLEVEL_ONLY) {
if (ipFingerprintFactor > 0 && requestLimitInBytes > 0 && requestSizeByFingerprint > requestLimitInBytes) {
String msg = "limit in Mode.TEXTLEVEL_ONLY: " + requestLimitInBytes + " / " + requestLimitPeriodInSeconds + ", request size: " + requestSizeByIp + ", ip: " + ipAddress + ", fingerprint: " + fingerprint;
throw new TooManyRequestsException("Client request size limit of " + requestLimitInBytes + " bytes per " +
requestLimitPeriodInSeconds + " seconds exceeded in text-level checks");
}
if (requestLimitInBytes > 0 && requestSizeByIp > ipRequestLimitInBytes) {
String msg = "limit in Mode.TEXTLEVEL_ONLY: " + ipRequestLimitInBytes + " / " + requestLimitPeriodInSeconds + ", request size: " + requestSizeByIp + ", ip: " + ipAddress + ", fingerprint: " + fingerprint;
throw new TooManyRequestsException("IP request size limit of " + ipRequestLimitInBytes + " bytes per " +
requestLimitPeriodInSeconds + " seconds exceeded in text-level checks");
}
} else {
if (ipFingerprintFactor > 0 && requestLimitInBytes > 0 && requestSizeByFingerprint > requestLimitInBytes) {
String msg = "limit: " + requestLimitInBytes + " / " + requestLimitPeriodInSeconds + ", request size: " + requestSizeByIp + ", ip: " + ipAddress + ", fingerprint: " + fingerprint;
throw new TooManyRequestsException("Client request size limit of " + requestLimitInBytes + " bytes per " +
requestLimitPeriodInSeconds + " seconds exceeded");
}
if (requestLimitInBytes > 0 && requestSizeByIp > ipRequestLimitInBytes) {
String msg = "limit: " + ipRequestLimitInBytes + " / " + requestLimitPeriodInSeconds + ", request size: " + requestSizeByIp + ", ip: " + ipAddress + ", fingerprint: " + fingerprint;
throw new TooManyRequestsException("IP request size limit of " + ipRequestLimitInBytes + " bytes per " +
requestLimitPeriodInSeconds + " seconds exceeded");
}
}
}
}
}
View on GitHub (pinned to 2e990059ce)