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.
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)
Solutions
- Check the remote BERT scorer is running and the configured host/port is correct.
- Increase the gRPC deadline for large batches or slow networks.
- Reduce batch size to lower per-call latency below the deadline.
- Inspect the wrapped/rethrown message for the actual gRPC status (UNAVAILABLE, DEADLINE_EXCEEDED) and address it (network, auth, server health).
- 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
- Health-check the gRPC scorer before heavy use
- Size batches so they finish within the deadline
- Set generous deadlines for cold starts
- Retry transient UNAVAILABLE with backoff
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.