languagetool-org/languagetool · error · TimeoutException

${e.getMessage()}

Error message

${e.getMessage()}

What it means

RemoteLanguageModel.batchScore calls a gRPC BERT scoring service; on StatusRuntimeException the method converts DEADLINE_EXCEEDED into a TimeoutException carrying the original message. Any other status (UNAVAILABLE, PERMISSION_DENIED, etc.) is rethrown unchanged. So this message is the raw gRPC status message, surfaced when the remote scorer fails or times out.

Solutions

  1. Check the remote BERT scorer is running and the configured host/port is correct.
  2. Increase the gRPC deadline for large batches or slow networks.
  3. Reduce batch size to lower per-call latency below the deadline.
  4. Inspect the wrapped/rethrown message for the actual gRPC status (UNAVAILABLE, DEADLINE_EXCEEDED) and address it (network, auth, server health).
  5. Add client-side retry with backoff for transient UNAVAILABLE statuses.

Example fix

// before
stub = RemoteLanguageModelProtocolServiceGrpc.newBlockingStub(channel);
List<List<Double>> r = model.batchScore(batch);
// after: smaller batch + longer deadline
stub = RemoteLanguageModelProtocolServiceGrpc.newBlockingStub(channel)
    .withDeadlineAfter(120, TimeUnit.SECONDS);
List<List<Double>> r = model.batchScore(smallerBatch);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!isServerReachable(host, port))
  throw new IllegalStateException("BERT scorer not reachable at " + host + ":" + port);

Try / catch

try {
  results = model.batchScore(batch);
} catch (TimeoutException e) {
  // retry with smaller batch / longer deadline
} catch (StatusRuntimeException e) {
  // check e.getStatus().getCode(); alert on UNAVAILABLE
}

Prevention

When it happens

Trigger: Calling batchScore() when the remote gRPC service is unreachable, overloaded, slow (exceeding the deadline), or rejects the call; the stub throws StatusRuntimeException which is either wrapped as TimeoutException or rethrown with its message.

Common situations: BERT scoring server not running or on wrong host/port, network latency causing the gRPC deadline to expire, server crash mid-request, TLS/auth failure to the scorer service.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at languagetool-core/src/main/java/org/languagetool/languagemodel/bert/RemoteLanguageModel.java:154

    }
    BatchScoreRequest batch = BatchScoreRequest.newBuilder().addAllRequests(
      uncachedRequests.stream().map(Request::convert).collect(Collectors.toList())
    ).build();
    // TODO multiple masks
    List<List<Double>> nonCacheResult;
    try {
      BertLmBlockingStub stub;
      if (timeoutMilliseconds > 0) {
        stub = model.withDeadlineAfter(timeoutMilliseconds, TimeUnit.MILLISECONDS);
      } else {
        stub = model;
      }
      nonCacheResult = stub.batchScore(batch)
        .getResponsesList().stream().map(r ->
          r.getScoresList().get(0).getScoreList()).collect(Collectors.toList());
    } catch (StatusRuntimeException e) {
      if (e.getStatus().getCode() == Status.DEADLINE_EXCEEDED.getCode()) {
        throw new TimeoutException(e.getMessage());
      } else {
        throw e;
      }
    }
    //
    List<List<Double>> allResults = new ArrayList<>();
    int i = 0;
    for (Request request : requests) {
      List<Double> result = cachedRequests.get(request);
      if (result != null) {
        //System.out.println("Adding result from cache");
        allResults.add(result);
      } else {
        //System.out.println("Adding result from remote");
        allResults.add(nonCacheResult.get(i++));
      }
    }

View on GitHub (pinned to 2e990059ce)