From dc3837c5de684ce2775bf229c0e3e18c70b61a02 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Tue, 23 Jun 2026 21:39:06 -0700 Subject: [PATCH 1/2] Added TransportException and tests for it --- .../client/api/ClientException.java | 4 ++++ .../client/api/TransportException.java | 13 +++++++++++ .../api/internal/HttpAPIClientHelper.java | 3 ++- .../clickhouse/client/ErrorHandlingTests.java | 23 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 client-v2/src/main/java/com/clickhouse/client/api/TransportException.java diff --git a/client-v2/src/main/java/com/clickhouse/client/api/ClientException.java b/client-v2/src/main/java/com/clickhouse/client/api/ClientException.java index 7a967f816..fe46aaa4f 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/ClientException.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/ClientException.java @@ -9,4 +9,8 @@ public ClientException(String message) { public ClientException(String message, Throwable cause) { super(message, cause); } + + public ClientException(String message, Throwable cause, String queryId) { + super(message, cause, queryId); + } } diff --git a/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java b/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java new file mode 100644 index 000000000..9124d3789 --- /dev/null +++ b/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java @@ -0,0 +1,13 @@ +package com.clickhouse.client.api; + +/** + * Any exception that happens inside transport logic and hard to categorize as client logic + * like connection initiation or data transfer. These exceptions are not retriable normally. + * Main purpose of this exception is to wrap transport specific. + */ +public class TransportException extends ClickHouseException { + public TransportException(String message, Throwable cause, String queryId) { + super(message, cause, queryId); + this.isRetryable = false; + } +} diff --git a/client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java b/client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java index 2e572e3da..ab4b0153c 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java @@ -10,6 +10,7 @@ import com.clickhouse.client.api.ConnectionReuseStrategy; import com.clickhouse.client.api.DataTransferException; import com.clickhouse.client.api.ServerException; +import com.clickhouse.client.api.TransportException; import com.clickhouse.client.api.enums.ProxyType; import com.clickhouse.client.api.enums.SSLMode; import com.clickhouse.client.api.http.ClickHouseHttpProto; @@ -897,7 +898,7 @@ public RuntimeException wrapException(String message, Exception cause, String qu } if (cause instanceof SSLException) { - return new ClickHouseException("SSL Problem", cause, queryId); + return new TransportException("SSL Problem", cause, queryId); } if (cause instanceof ConnectionRequestTimeoutException || diff --git a/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java b/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java index 314e8c309..e9a78b47a 100644 --- a/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java +++ b/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java @@ -3,9 +3,11 @@ import com.clickhouse.client.api.Client; import com.clickhouse.client.api.DataTransferException; import com.clickhouse.client.api.ServerException; +import com.clickhouse.client.api.TransportException; import com.clickhouse.client.api.enums.Protocol; import com.clickhouse.client.api.query.QuerySettings; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.Test; import java.time.temporal.ChronoUnit; @@ -74,6 +76,27 @@ void testQueryTimeout() throws Exception { } } + @Test(groups = {"integration"}) + void testTransportException() throws Exception { + if (isCloud()) { + throw new SkipException("SSL Configuration tests - no need to test on cloud"); + } + + ClickHouseNode secureServer = getSecureServer(ClickHouseProtocol.HTTP); + + try (Client client = new Client.Builder() + .addEndpoint("https://localhost:" + secureServer.getPort()) + .setUsername("default") + .setPassword(ClickHouseServerForTest.getPassword()) + .compressClientRequest(true) + .build()) { + + TransportException tex = Assert.expectThrows(TransportException.class, + () -> client.query("SELECT 1").get()); + Assert.assertTrue(tex.getMessage().contains("SSL Problem")); + } + } + protected Client.Builder newClient() { ClickHouseNode node = getServer(ClickHouseProtocol.HTTP); boolean isSecure = isCloud(); From f7db286180e69ca55acda76957c6a444e6bf609d Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Thu, 25 Jun 2026 10:25:08 -0700 Subject: [PATCH 2/2] Fixed javadoc and improved test --- .../com/clickhouse/client/api/TransportException.java | 6 +++--- .../java/com/clickhouse/client/ErrorHandlingTests.java | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java b/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java index 9124d3789..bd4dcce1b 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/TransportException.java @@ -1,9 +1,9 @@ package com.clickhouse.client.api; /** - * Any exception that happens inside transport logic and hard to categorize as client logic - * like connection initiation or data transfer. These exceptions are not retriable normally. - * Main purpose of this exception is to wrap transport specific. + * Transport-layer exception that is hard to categorize as connection initiation or data transfer. + * These exceptions are not retryable by default. + * Main purpose of this exception is to wrap transport-specific failures (e.g., SSL errors). */ public class TransportException extends ClickHouseException { public TransportException(String message, Throwable cause, String queryId) { diff --git a/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java b/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java index e9a78b47a..a0035afc8 100644 --- a/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java +++ b/client-v2/src/test/java/com/clickhouse/client/ErrorHandlingTests.java @@ -91,9 +91,13 @@ void testTransportException() throws Exception { .compressClientRequest(true) .build()) { + final String queryId = "test-failure-query-id"; TransportException tex = Assert.expectThrows(TransportException.class, - () -> client.query("SELECT 1").get()); - Assert.assertTrue(tex.getMessage().contains("SSL Problem")); + () -> client.query("SELECT 1", new QuerySettings().setQueryId(queryId)).get()); + Assert.assertTrue(tex.getMessage().startsWith("SSL Problem"), "Unexpected message: " + tex.getMessage()); + Assert.assertEquals(tex.getQueryId(), queryId); + Assert.assertTrue(tex.getCause() instanceof javax.net.ssl.SSLException, + "Expected SSLException cause but was: " + tex.getCause()); } }