Search code examples
javaamazon-web-serviceskotlinamazon-dynamodbamazon-dynamodb-local

DynamoDB: Using putItem with empty strings failing


According to the docs here I should be able to put an item with one of my non-key attributes as an empty String.

I have primarily been using Kotlin but also have tested out in Java and I am unable to write an empty String. I am seeing the following error:

Exception in thread "main" java.util.concurrent.ExecutionException: software.amazon.awssdk.services.dynamodb.model.DynamoDbException: One or more parameter values were invalid: An AttributeValue may not contain an empty string (Service: DynamoDb, Status Code: 400, Request ID: 741fa685-4c6b-40d3-9c48-edaeeb5ca513, Extended Request ID: null)
    at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
    at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2070)
    at dynamo.DynamoClient.putData(DynamoClient.kt:64)
    at dynamo.DynamoClientKt.main(DynamoClient.kt:317)
    at dynamo.DynamoClientKt$$$main.invoke(Unknown Source)
    at kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$1.invokeSuspend(IntrinsicsJvm.kt:199)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:114)
    at kotlin.coroutines.jvm.internal.RunSuspendKt.runSuspend(RunSuspend.kt:19)
    at dynamo.DynamoClientKt.main(DynamoClient.kt)
Caused by: software.amazon.awssdk.services.dynamodb.model.DynamoDbException: One or more parameter values were invalid: An AttributeValue may not contain an empty string (Service: DynamoDb, Status Code: 400, Request ID: 741fa685-4c6b-40d3-9c48-edaeeb5ca513, Extended Request ID: null)
    at software.amazon.awssdk.services.dynamodb.model.DynamoDbException$BuilderImpl.build(DynamoDbException.java:95)
    at software.amazon.awssdk.services.dynamodb.model.DynamoDbException$BuilderImpl.build(DynamoDbException.java:55)
    at software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonProtocolErrorUnmarshaller.unmarshall(AwsJsonProtocolErrorUnmarshaller.java:89)
    at software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonProtocolErrorUnmarshaller.handle(AwsJsonProtocolErrorUnmarshaller.java:63)
    at software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonProtocolErrorUnmarshaller.handle(AwsJsonProtocolErrorUnmarshaller.java:42)
    at software.amazon.awssdk.core.http.MetricCollectingHttpResponseHandler.lambda$handle$0(MetricCollectingHttpResponseHandler.java:52)
    at software.amazon.awssdk.core.internal.util.MetricUtils.measureDurationUnsafe(MetricUtils.java:64)
    at software.amazon.awssdk.core.http.MetricCollectingHttpResponseHandler.handle(MetricCollectingHttpResponseHandler.java:52)
    at software.amazon.awssdk.core.internal.http.async.AsyncResponseHandler.lambda$prepare$0(AsyncResponseHandler.java:88)
    at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1146)
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
    at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2144)
    at software.amazon.awssdk.core.internal.http.async.AsyncResponseHandler$BaosSubscriber.onComplete(AsyncResponseHandler.java:129)
    at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler.runAndLogError(ResponseHandler.java:179)
    at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler.access$500(ResponseHandler.java:69)
    at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler$PublisherAdapter$1.onComplete(ResponseHandler.java:295)
    at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.publishMessage(HandlerPublisher.java:402)
    at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.flushBuffer(HandlerPublisher.java:338)
    at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.receivedDemand(HandlerPublisher.java:291)
    at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.access$200(HandlerPublisher.java:61)
    at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher$ChannelSubscription$1.run(HandlerPublisher.java:495)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at java.base/java.lang.Thread.run(Thread.java:835)

Process finished with exit code 1

I am using the latest version of the SDK, version 2.13.55

Here is some sample code in Java:

import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

public class DynamoTest {
    public void test() throws MalformedURLException, URISyntaxException, ExecutionException, InterruptedException {
        String host = "http://localhost:2223";
        URI uriHost = new URL(host).toURI();

        DynamoDbAsyncClient client = DynamoDbAsyncClient
                .builder()
                .endpointOverride(uriHost)
                .credentialsProvider(
                        DefaultCredentialsProvider.create()
                )
                .region(Region.US_EAST_1)
                .build();

        Map<String, AttributeValue> mapValues = new HashMap<>();
        mapValues.put("pk", AttributeValue.builder().s("FAKE_PK").build());
        mapValues.put("sk", AttributeValue.builder().s("1").build());
        mapValues.put("failingEmptyStr", AttributeValue.builder().s("").build());

        PutItemRequest putItem = PutItemRequest
                .builder()
                .item(mapValues)
                .tableName("test-table")
                .build();

        client.putItem(putItem).get();
    }

    public static void main(String[] args) throws MalformedURLException, URISyntaxException, ExecutionException, InterruptedException {
        new DynamoTest().test();
    }
}

Solution

  • It looks like you are using DynamoDB Local. Update the version to the newest as it does support empty strings. it was released at the same time as the feature in DynamoDB proper.