languagetool-org/languagetool · warning · TooManyRequestsException
Client request size limit of bytes per seconds exceeded
Error message
Client request size limit of bytes per seconds exceeded
What it means
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.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java:240
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");
}
}
}
}
}
protected static class RequestEvent {
private final String ip;
private final Date date;
private final int sizeInBytes;
private final String fingerprint;View on GitHub (pinned to 2e990059ce)
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
Example fix
// before resp = check(mode="all", text=wholeBook); // after chunks = split(wholeBook, 20000); for c in chunks: checkWithBackoff(mode="all", text=c);
Defensive patterns
Strategy: retry
Validate before calling
if (new Blob([text]).size > MAX_CHUNK_BYTES) text = chunk(text, MAX_CHUNK_BYTES);
Try / catch
try {
return await check(text, mode);
} catch (e) {
if (e.status === 429) { await exponentialBackoff(); return check(text, mode); }
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Client request size limit of bytes per seconds exceeded in
- IP request size limit of bytes per seconds exceeded in tex
- 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/0620d5408eaf5c3c.
Report an issue: GitHub.