Aws-sdk-java-v2: KinesisClient getRecords throws SdkClientException caused by NPE

Created on 21 Nov 2018  路  3Comments  路  Source: aws/aws-sdk-java-v2

While migrating an application from SDK v1 to SDK v2 I got an unexpected error.

When calling getRecords with the default client (KinesisClient.create();) a SdkClientException with the following message is thrown: Unable to unmarshall response (bytes must not be null.). Response Code: 200, Response Text: OK.

The error is not thrown if SdkSystemSetting.CBOR_ENABLED.property() is set to false.

Expected Behavior

Expect to get a successful GetRecordsResponse.

Current Behavior

Stack-trace:

software.amazon.awssdk.core.exception.SdkClientException: Unable to unmarshall response (bytes must not be null.). Response Code: 200, Response Text: OK
at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97)
at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.handleSuccessResponse(HandleResponseStage.java:100)
at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.handleResponse(HandleResponseStage.java:70)
at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.execute(HandleResponseStage.java:58)
at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.execute(HandleResponseStage.java:41)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:205)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:63)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:36)
at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:77)
at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:39)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage$RetryExecutor.doExecute(RetryableStage.java:115)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage$RetryExecutor.execute(RetryableStage.java:88)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:64)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:44)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:205)
at software.amazon.awssdk.core.internal.http.StreamManagingStage.execute(StreamManagingStage.java:51)
at software.amazon.awssdk.core.internal.http.StreamManagingStage.execute(StreamManagingStage.java:33)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.executeWithTimer(ApiCallTimeoutTrackingStage.java:79)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.execute(ApiCallTimeoutTrackingStage.java:60)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.execute(ApiCallTimeoutTrackingStage.java:42)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:205)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:205)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ExecutionFailureExceptionReportingStage.execute(ExecutionFailureExceptionReportingStage.java:37)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ExecutionFailureExceptionReportingStage.execute(ExecutionFailureExceptionReportingStage.java:25)
at software.amazon.awssdk.core.internal.http.AmazonSyncHttpClient$RequestExecutionBuilderImpl.execute(AmazonSyncHttpClient.java:240)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.invoke(BaseSyncClientHandler.java:96)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:120)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:73)
at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55)
at software.amazon.awssdk.services.kinesis.DefaultKinesisClient.getRecords(DefaultKinesisClient.java:901)
at <redacted_package_and_class>$Reader.run(<my-own-class>.java:65)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: bytes must not be null.
at software.amazon.awssdk.utils.Validate.paramNotNull(Validate.java:117)
at software.amazon.awssdk.core.SdkBytes.fromByteArray(SdkBytes.java:71)
at software.amazon.awssdk.protocols.core.StringToValueConverter.toSdkBytes(StringToValueConverter.java:93)
at software.amazon.awssdk.protocols.core.StringToValueConverter$SimpleStringToValue.convert(StringToValueConverter.java:58)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller$SimpleTypeJsonUnmarshaller.unmarshall(JsonProtocolUnmarshaller.java:145)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.unmarshallStructured(JsonProtocolUnmarshaller.java:195)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.unmarshallStructured(JsonProtocolUnmarshaller.java:99)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.lambda$unmarshallList$2(JsonProtocolUnmarshaller.java:128)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.unmarshallList(JsonProtocolUnmarshaller.java:130)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.unmarshallStructured(JsonProtocolUnmarshaller.java:195)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.unmarshall(JsonProtocolUnmarshaller.java:182)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller.unmarshall(JsonProtocolUnmarshaller.java:153)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonResponseHandler.handle(JsonResponseHandler.java:79)
at software.amazon.awssdk.protocols.json.internal.unmarshall.JsonResponseHandler.handle(JsonResponseHandler.java:36)
at software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonResponseHandler.handle(AwsJsonResponseHandler.java:43)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler$Crc32ValidationResponseHandler.handle(AwsSyncClientHandler.java:88)
at software.amazon.awssdk.core.client.handler.BaseClientHandler.lambda$interceptorCalling$2(BaseClientHandler.java:117)
at software.amazon.awssdk.core.client.handler.AttachHttpMetadataResponseHandler.handle(AttachHttpMetadataResponseHandler.java:40)
at software.amazon.awssdk.core.client.handler.AttachHttpMetadataResponseHandler.handle(AttachHttpMetadataResponseHandler.java:28)
at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.handleSuccessResponse(HandleResponseStage.java:89)
... 37 common frames omitted

Possible Solution

If this is not a bug, I'd appreciate feedback if there is some setting I've missed, or error made.

Steps to Reproduce (for bugs)

I tried to create a minimal self-contained test.
The following code runs in a project with the following dependencies:

  <dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>kinesis</artifactId>
      <version>2.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.25</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>log4j-over-slf4j</artifactId>
      <version>1.7.25</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>6.14.3</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

Code that fails with the error described above:

    @Test
    public void testGetRecordsCborEnabled() throws InterruptedException {
        System.setProperty(SdkSystemSetting.CBOR_ENABLED.property(), "true");


        KinesisClient kinesisClient = KinesisClient.create();
        String streamName = "my-stream-name";


        DescribeStreamRequest describeStreamRequest = DescribeStreamRequest.builder().streamName(streamName).build();
        List<Shard> shards = kinesisClient.describeStream(describeStreamRequest)
                .streamDescription()
                .shards();

        GetShardIteratorRequest shardIteratorRequest = GetShardIteratorRequest.builder()
                .shardId(shards.get(0).shardId())
                .shardIteratorType(ShardIteratorType.LATEST)
                .streamName(streamName)
                .build();

        String shardIterator =  kinesisClient.getShardIterator(shardIteratorRequest).shardIterator();

        kinesisClient.putRecord(PutRecordRequest.builder()
                .data(SdkBytes.fromUtf8String("{\"code\": 200, \"message\": \"this should work\"}"))
                .streamName(streamName)
                .partitionKey("partition")
                .build());

        TimeUnit.MILLISECONDS.sleep(100L);


        GetRecordsResponse getResponse = kinesisClient.getRecords(GetRecordsRequest.builder()
                .limit(100)
                .shardIterator(shardIterator)
                .build()
        );

        Assert.assertEquals(getResponse.records().size(), 1);
        Record record = getResponse.records().get(0);
        Assert.assertEquals(record.data().asUtf8String(), "{\"code\": 200, \"message\": \"this should work\"}");
    }

Setting CBOR_ENABLED to false allows the code to run fine.

Context

I migrated an application from SDK v1 to v2 when I stumbled into this issue.
Missing proper integration-test allowed the code to reach a QA-environment where the issue was first noticed. My local environment is specified in the next section.
The container in the environment had the following java specification:

openjdk version "1.8.0_181"
OpenJDK Runtime Environment (IcedTea 3.9.0) (Alpine 8.181.13-r0)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)

A hunch told me it might be CBOR related, so I tried disabling it, and it now read records as expected.

Your Environment

  • AWS Java SDK version used: 2.1.0
  • JDK version used: 1.8.0_162
  • Operating System and version: macOS Sierra (10.12.6)
bug

Most helpful comment

I'm facing to something similar while I use a S3Client:

GetObjectResponse response = client.getObject(request, Paths.get(contentPath));

A SdkClientException:

Unable to unmarshall response (null). Response Code: 200, Response Text: OK

All 3 comments

Was able to repro this. Interestingly enough we had a test that would have caught this but it wasn't running due to our name filters. Anyways, working on the fix.

This has been fixed and will be available in our next release (probably next week sometime). Thanks for the detailed report!

I'm facing to something similar while I use a S3Client:

GetObjectResponse response = client.getObject(request, Paths.get(contentPath));

A SdkClientException:

Unable to unmarshall response (null). Response Code: 200, Response Text: OK
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ochrons picture ochrons  路  6Comments

shorea picture shorea  路  4Comments

deepankerk picture deepankerk  路  5Comments

david-katz picture david-katz  路  3Comments

tigertoes picture tigertoes  路  6Comments