Java HttpClient timeout: no default, so set two of them

Java's HttpClient has no request timeout unless you set one: connectTimeout on the client, timeout on each request, and HttpTimeoutException.

5 min readSume
All posts

The Java HttpClient (java.net.http, since Java 11) has no request timeout by default: the javadoc says not setting one is the same as an infinite duration, so send blocks forever if no response comes. Set two timeouts: HttpClient.Builder.connectTimeout(Duration) for opening a connection, and HttpRequest.Builder.timeout(Duration) for each request's response. When one expires, send throws HttpTimeoutException, or HttpConnectTimeoutException for the connect phase.

Java facts come from the Java SE 21 javadoc for HttpClient, HttpClient.Builder, HttpRequest.Builder and HttpTimeoutException. The slow-API example is Sume's, from Jobs and results and Video Generation, all read on 2026-09-29.

What are the Java HttpClient timeout settings?

There are two, set in two places, and HttpClient.newHttpClient() sets neither.

From the Java SE 21 javadoc for HttpClient.Builder, HttpRequest.Builder and HttpClient, read 2026-09-29.
SettingCoversIf not setOn expiry
HttpClient.Builder.connectTimeout(Duration)Establishing a new connection; no effect when a connection is reusedconnectTimeout() returns an empty OptionalHttpConnectTimeoutException
HttpRequest.Builder.timeout(Duration)Receiving the response to this requestSame as an infinite duration: block foreverHttpTimeoutException

How do I set a timeout on a Java HttpClient request?

Put connectTimeout on the client you reuse and timeout on each request. A non-positive duration makes timeout throw IllegalArgumentException. HttpConnectTimeoutException extends HttpTimeoutException, which extends IOException, so catch the narrower one first. With sendAsync, the future completes exceptionally with the same exceptions instead.

HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))    // new connections only
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sume.com/v1/videos"))
    .timeout(Duration.ofSeconds(30))           // this request's response
    .header("Authorization", "Bearer " + System.getenv("SUME_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "order-8823-clip-v1")
    .POST(HttpRequest.BodyPublishers.ofString(
        "{\"model\":\"sume/auto\",\"prompt\":\"A product clip on a desk\",\"aspect_ratio\":\"9:16\",\"duration\":5}"))
    .build();

try {
    HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(res.statusCode() + " " + res.body()); // 202: id, polling_url
} catch (HttpConnectTimeoutException e) {
    // no connection within 10 s: retry with the same Idempotency-Key
} catch (HttpTimeoutException e) {
    // no response within 30 s: the job may exist; retry with the same key
}

How long should the timeout be for a slow API?

Short, because an async job API answers before the work is done. Sume's video create returns a job id and polling URL immediately, and you poll GET /v1/videos/{jobId} until the status is completed. Where a Sume submit endpoint offers the blocking sync mode, it waits at most 30 seconds and then returns the job, so no create call needs a request timeout measured in minutes. Put the long deadline in your polling loop instead: Sume's jobs guide calls 20 minutes reasonable for video, and says that deadline is client-side.

Give each status poll the same short per-request timeout, and treat an HttpTimeoutException on a poll as one missed read, not a failed job: wait with exponential backoff and poll again, and stop only when the status is terminal. The connect timeout matters less here, because it has no effect when the client reuses an open connection.

What happens to the job when HttpClient times out?

It keeps running. A client-side timeout does not cancel the job; it keeps running and still bills. Keep the job id and pick it back up from the status URL, and don't resubmit the paid request because a local process timed out. If the create timed out before you saw an id, resend it with the same Idempotency-Key, and the retry returns the original job instead of billing a second one. Spring Retry for paid API calls wraps that retry, and text to speech API in Java shows a full submit-and-poll loop.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume