languagetool-org/languagetool · warning · TooManyRequestsException
IP request size limit of bytes per seconds exceeded in tex
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.
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)
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 in
- Client request size limit of bytes per seconds exceeded
- IP request size limit of bytes per seconds exceeded
- User request limit of per day exceeded. Try again after mid
- Whitelist 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.