From 8d23ed8cd50d3a3a6bc61fb68eab88276db15e51 Mon Sep 17 00:00:00 2001 From: Yun Wang Date: Wed, 12 Aug 2026 19:40:42 +0200 Subject: [PATCH 1/2] fix: name the HTTP status when the error body is not JSON An unparseable error body produced the message "failed to parse error response", which hid the HTTP status. The message now appends the status to that text, so prefix matching and substring matching both keep working. The status code, the raw response body and the parse cause do not change. The build(ResponseBody) overload keeps the old message, because it does not receive the status. --- src/main/java/io/getstream/exceptions/StreamException.java | 3 ++- src/test/java/io/getstream/StreamErrorHandlingTest.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/getstream/exceptions/StreamException.java b/src/main/java/io/getstream/exceptions/StreamException.java index 0378e1ad..2cb3d63c 100644 --- a/src/main/java/io/getstream/exceptions/StreamException.java +++ b/src/main/java/io/getstream/exceptions/StreamException.java @@ -106,7 +106,8 @@ public static StreamException build(Response httpResponse) { if (parsed == null) { String msg = parseCause != null - ? "failed to parse error response" + ? String.format( + "failed to parse error response: unexpected server response code %d", status) : String.format("Unexpected server response code %d", status); if (status == 429) { return new StreamRateLimitException( diff --git a/src/test/java/io/getstream/StreamErrorHandlingTest.java b/src/test/java/io/getstream/StreamErrorHandlingTest.java index 753a8db7..c0a0ff05 100644 --- a/src/test/java/io/getstream/StreamErrorHandlingTest.java +++ b/src/test/java/io/getstream/StreamErrorHandlingTest.java @@ -107,7 +107,8 @@ void apiUnparseableBody_setsRawBodyAndZeroCode() { StreamApiException e = assertThrows(StreamApiException.class, () -> request().execute()); assertEquals(502, e.getStatusCode(), "status code preserved when body is unparseable"); assertEquals(0, e.getCode(), "unparseable body → code 0"); - assertEquals("failed to parse error response", e.getMessage()); + assertEquals( + "failed to parse error response: unexpected server response code 502", e.getMessage()); assertEquals("bad gateway", e.getRawResponseBody()); assertNotNull(e.getCause(), "parse error preserved on cause chain"); } From 1404cc0c7997248634e756f598b13cbcaa44fe0d Mon Sep 17 00:00:00 2001 From: Yun Wang Date: Wed, 12 Aug 2026 20:34:56 +0200 Subject: [PATCH 2/2] test: give the ban tests their own target user ModerationTest banned the shared testUserId for 60 minutes, and a banned user cannot add an activity. The two tests that create an activity as that user failed whenever they ran after the ban test. The ban and unban tests now target a dedicated user. --- src/test/java/io/getstream/ModerationTest.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/test/java/io/getstream/ModerationTest.java b/src/test/java/io/getstream/ModerationTest.java index 275ffb51..5e75164c 100644 --- a/src/test/java/io/getstream/ModerationTest.java +++ b/src/test/java/io/getstream/ModerationTest.java @@ -21,6 +21,10 @@ public class ModerationTest { static String testUserId; static String testUserId2; static String testModeratorId; + // The ban tests need their own target. A global ban on testUserId survives for + // the rest of the class, and a banned user cannot add an activity, so the + // activity tests failed whenever they ran after the ban. + static String bannedUserId; static String testFeedId; static String testActivityId; @@ -34,6 +38,7 @@ static void setup() throws Exception { testUserId = "test-user-" + RandomStringUtils.randomAlphanumeric(8); testUserId2 = "test-user-2-" + RandomStringUtils.randomAlphanumeric(8); testModeratorId = "moderator-" + RandomStringUtils.randomAlphanumeric(8); + bannedUserId = "banned-user-" + RandomStringUtils.randomAlphanumeric(8); Map usersMap = new HashMap<>(); usersMap.put( @@ -53,6 +58,13 @@ static void setup() throws Exception { .name("Moderator " + testModeratorId) .role("admin") .build()); + usersMap.put( + bannedUserId, + UserRequest.builder() + .id(bannedUserId) + .name("Banned User " + bannedUserId) + .role("user") + .build()); UpdateUsersRequest updateUsersRequest = UpdateUsersRequest.builder().users(usersMap).build(); client.updateUsers(updateUsersRequest).execute(); @@ -71,7 +83,7 @@ void testBanWithReason() throws Exception { // snippet-start: BanWithReason BanRequest request = BanRequest.builder() - .targetUserID(testUserId) + .targetUserID(bannedUserId) .reason("spam") .timeout(60) // 60 minutes .bannedByID(testModeratorId) @@ -206,7 +218,7 @@ void testUnbanUser() throws Exception { // First ban the user BanRequest banRequest = BanRequest.builder() - .targetUserID(testUserId) + .targetUserID(bannedUserId) .reason("test") .bannedByID(testModeratorId) .build(); @@ -214,7 +226,7 @@ void testUnbanUser() throws Exception { // snippet-start: UnbanUser UnbanRequest request = - UnbanRequest.builder().TargetUserID(testUserId).unbannedByID(testModeratorId).build(); + UnbanRequest.builder().TargetUserID(bannedUserId).unbannedByID(testModeratorId).build(); UnbanResponse response = moderation.unban(request).execute().getData(); // snippet-end: UnbanUser