languagetool-org/languagetool · warning · TooManyRequestsException

IP request size limit of bytes per seconds exceeded

Error message

IP request size limit of  bytes per  seconds exceeded

What it means

Outside TEXTLEVEL_ONLY mode, RequestLimiter enforces a per-IP request-size quota. When total bytes from one IP exceed ipRequestLimitInBytes within requestLimitPeriodInSeconds, checkLimit throws TooManyRequestsException (HTTP 429). This caps aggregate upload volume per client IP for all check modes.

Source

Thrown at languagetool-server/src/main/java/org/languagetool/server/RequestLimiter.java:245

          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;
    private final JLanguageTool.Mode mode;

    RequestEvent(String ip, Date date, int sizeInBytes, String fingerprint, JLanguageTool.Mode mode) {
      this.ip = ip;
      this.date = new Date(date.getTime());

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Pause until requestLimitPeriodInSeconds elapses, then resume slowly
  2. Implement exponential backoff on 429 and cap total bytes sent per IP per window
  3. Use Premium credentials for higher limits, or distribute calls across IPs
  4. Server admins: raise ipRequestLimitInBytes in HTTPServerConfig / launch arguments
  5. Batch and deduplicate texts before sending to reduce total bytes

Example fix

// before: immediate retry on 429
catch (e) { check(text); }
// after
catch (TooManyRequests/429 e) { sleep(backoff); backoff *= 2; retry(); }
Defensive patterns

Strategy: retry

Validate before calling

function withinIpBudget(bytes) { return ipBytesWindow + bytes <= ipRequestLimitInBytes; }

Try / catch

catch (err) {
  if (err instanceof HttpError && err.status === 429) {
    await sleep(backoffMs); backoffMs = Math.min(backoffMs * 2, MAX_BACKOFF);
    return attempt();
  }
  throw err;
}

Prevention

When it happens

Trigger: POSTing to /v2/check (any non-textLevelOnly mode) where cumulative bytes from the client IP exceed ipRequestLimitInBytes within requestLimitPeriodInSeconds and requestLimitInBytes > 0.

Common situations: Server-side integrations routing many users through one outbound IP; scheduled jobs re-uploading the same corpora; retries without backoff after a 429; tight ipRequestLimitInBytes in self-hosted config.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/a46b81f5c2eb61f4. Report an issue: GitHub.