Skip to content

Commit da3ed60

Browse files
authored
Improve error message thrown from mismatched checksum for S3 GetObject (#6773)
1 parent 3c4b2b8 commit da3ed60

6 files changed

Lines changed: 29 additions & 10 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "bugfix",
3+
"category": "Amazon S3",
4+
"contributor": "",
5+
"description": "Fixed misleading checksum mismatch error message for S3 GetObject that incorrectly referenced uploading. See [#6324](https://github.com/aws/aws-sdk-java-v2/issues/6324)."
6+
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/checksums/ChecksumConstant.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ public final class ChecksumConstant {
5555
*/
5656
public static final int S3_MD5_CHECKSUM_LENGTH = 16;
5757

58+
public static final String CHECKSUM_MISMATCH_ERROR_MESSAGE_TEMPLATE =
59+
"Data read has a different checksum than expected. Was 0x%s, "
60+
+ "but expected 0x%s. Common causes: (1) The data was corrupted during transfer between S3 and the client. "
61+
+ "(2) A custom ExecutionInterceptor modified the HTTP response content before checksum validation. "
62+
+ "Note: The response data may have already been delivered to the configured response transformer "
63+
+ "and should not be considered reliable.";
64+
5865
private ChecksumConstant() {
5966
}
6067
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/checksums/S3ChecksumValidatingInputStream.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.awssdk.services.s3.internal.checksums;
1717

18+
import static software.amazon.awssdk.services.s3.internal.checksums.ChecksumConstant.CHECKSUM_MISMATCH_ERROR_MESSAGE_TEMPLATE;
19+
1820
import java.io.IOException;
1921
import java.io.InputStream;
2022
import java.util.Arrays;
@@ -182,9 +184,8 @@ private void validateAndThrow() {
182184

183185
if (!Arrays.equals(computedChecksum, streamChecksum)) {
184186
throw RetryableException.create(
185-
String.format("Data read has a different checksum than expected. Was 0x%s, but expected 0x%s. " +
186-
"This commonly means that the data was corrupted between the client and " +
187-
"service.", BinaryUtils.toHex(computedChecksum), BinaryUtils.toHex(streamChecksum)));
187+
String.format(CHECKSUM_MISMATCH_ERROR_MESSAGE_TEMPLATE, BinaryUtils.toHex(computedChecksum),
188+
BinaryUtils.toHex(streamChecksum)));
188189
}
189190
}
190191

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/checksums/S3ChecksumValidatingPublisher.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package software.amazon.awssdk.services.s3.internal.checksums;
1717

1818
import static java.lang.Math.toIntExact;
19+
import static software.amazon.awssdk.services.s3.internal.checksums.ChecksumConstant.CHECKSUM_MISMATCH_ERROR_MESSAGE_TEMPLATE;
1920

2021
import java.nio.ByteBuffer;
2122
import java.util.Arrays;
@@ -135,12 +136,7 @@ public void onComplete() {
135136
byte[] computedChecksum = sdkChecksum.getChecksumBytes();
136137
if (!Arrays.equals(computedChecksum, streamChecksum)) {
137138
onError(RetryableException.create(
138-
String.format("Data read has a different checksum than expected. Was 0x%s, but expected 0x%s. "
139-
+ "Common causes: (1) You modified a request ByteBuffer before it could be "
140-
+ "written to the service. Please ensure your data source does not modify the "
141-
+ " byte buffers after you pass them to the SDK. (2) The data was corrupted between the "
142-
+ "client and service. Note: Despite this error, the upload still completed and was "
143-
+ "persisted in S3.",
139+
String.format(CHECKSUM_MISMATCH_ERROR_MESSAGE_TEMPLATE,
144140
BinaryUtils.toHex(computedChecksum), BinaryUtils.toHex(streamChecksum))));
145141
return; // Return after onError and not call onComplete below
146142
}

services/s3/src/test/java/software/amazon/awssdk/services/s3/checksums/S3ChecksumValidatingInputStreamTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.awssdk.services.s3.checksums;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
1920
import static org.junit.jupiter.api.Assertions.assertEquals;
2021
import static org.junit.jupiter.api.Assertions.fail;
@@ -107,7 +108,7 @@ public void invalidChecksumFails() throws IOException {
107108
IoUtils.toByteArray(validatingInputStream);
108109
fail("Corruption at byte " + i + " was not detected.");
109110
} catch (SdkClientException e) {
110-
// Expected
111+
assertThat(e.getMessage()).contains("Data read has a different checksum than expected");
111112
}
112113
}
113114
}

services/s3/src/test/java/software/amazon/awssdk/services/s3/checksums/S3ChecksumValidatingPublisherTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.awssdk.services.s3.checksums;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
1920
import static org.junit.jupiter.api.Assertions.assertFalse;
2021
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -91,6 +92,7 @@ public void testLastChecksumByteCorrupted() {
9192

9293
assertFalse(s.hasCompleted());
9394
assertTrue(s.isOnErrorCalled());
95+
assertThat(s.getError().getMessage()).contains("Data read has a different checksum than expected");
9496
}
9597

9698
@Test
@@ -195,6 +197,7 @@ private class TestSubscriber implements Subscriber<ByteBuffer> {
195197
final List<ByteBuffer> received;
196198
boolean completed;
197199
boolean onErrorCalled;
200+
Throwable error;
198201

199202
TestSubscriber() {
200203
this.received = new ArrayList<>();
@@ -216,6 +219,7 @@ public void onNext(ByteBuffer buffer) {
216219
@Override
217220
public void onError(Throwable t) {
218221
onErrorCalled = true;
222+
error = t;
219223
}
220224

221225
@Override
@@ -242,6 +246,10 @@ public boolean hasCompleted() {
242246
public boolean isOnErrorCalled() {
243247
return onErrorCalled;
244248
}
249+
250+
public Throwable getError() {
251+
return error;
252+
}
245253
}
246254

247255
private class TestPublisher implements Publisher<ByteBuffer> {

0 commit comments

Comments
 (0)