Mark J Miller
Mark J Miller

Reputation: 4871

DynamoDB put-item ConditionalCheckFailedException

Given the table schema defined below (create-table.json) I am getting the following error after I call put-item using add-event1.json followed by add-event2.json:

A client error (ConditionalCheckFailedException) occurred when calling the PutItem operation: The conditional request failed

Why doesn't the ConditionExpression allow me to write both records? (I expect to have 2 records after the second operation)

I suspected that it was because of the non-key conditions used, but I don't see anything in the docs that indicates a lack of support for non-key conditions.

Create Table

$ aws dynamodb create-table --cli-input-json file://create-table.json

create-table.json

{
    "TableName": "EVENTS_TEST",
    "KeySchema": [
      { "AttributeName": "aggregateId", "KeyType": "HASH" },
      { "AttributeName": "streamRevision", "KeyType": "RANGE" }
    ],
    "AttributeDefinitions": [
      { "AttributeName": "aggregateId", "AttributeType": "S" },
      { "AttributeName": "streamRevision", "AttributeType": "N" }
    ],
    "ProvisionedThroughput": {
      "ReadCapacityUnits": 10,
      "WriteCapacityUnits": 10
    }
 }

Add First Record

$ aws dynamodb put-item --cli-input-json file://add-event1.json

add-event1.json

{
  "TableName": "EVENTS_TEST",
  "Item": {
    "aggregateId": { "S": "id" },
    "id": { "S": "119" },
    "context": { "S": "*" },
    "aggregate": { "S": "*" },
    "streamRevision": { "N": "0" },
    "commitId": { "S": "1119" },
    "commitSequence": { "N": "0" },
    "commitStamp": { "N": "1470185631511" },
    "dispatched": { "BOOL": false },
    "payload": { "S": "{ \"event\": \"bla\" }" }
  },
  "ExpressionAttributeNames": { "#name": "aggregate" },
  "ConditionExpression": "attribute_not_exists(aggregateId) and attribute_not_exists(streamRevision) and #name <> :name and context <> :ctx",
  "ExpressionAttributeValues": {
    ":name": { "S": "*" },
    ":ctx": { "S": "*" }
  }
}

Add Second Record

$ aws dynamodb put-item --cli-input-json file://add-event2.json

add-event2.json

{
  "TableName": "EVENTS_TEST",
  "Item": {
    "aggregateId": { "S": "id" },
    "id": { "S": "123" },
    "context": { "S": "myCtx" },
    "aggregate": { "S": "myAgg" },
    "streamRevision": { "N": "0" },
    "commitId": { "S": "1123" },
    "commitSequence": { "N": "0" },
    "commitStamp": { "N": "1470185631551" },
    "dispatched": { "BOOL": false },
    "payload": { "S": "{ \"event\": \"bla2\" }" }
  },
  "ExpressionAttributeNames": { "#name": "aggregate" },
  "ConditionExpression": "aggregateId <> :id and streamRevision <> :rev and #name <> :name and context <> :ctx",
  "ExpressionAttributeValues": {
     ":id": { "S": "id" },
     ":rev": { "N": "0" },
     ":name": { "S": "myAgg" },
     ":ctx": { "S": "myCtx" }
  }
}

Upvotes: 23

Views: 120346

Answers (4)

crakama
crakama

Reputation: 825

In my case I got the error because I has Optimistic Lock in the database andaccording to official documentation in aws the client version of the table entry was different from what the server had, In my case there were two services accessing same database and modifying it.

Optimistic locking with version number - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html

ConditionalCheckFailedException is thrown if:

You use optimistic locking with @DynamoDBVersionAttribute and the version value on the server is different from the value on the client side.

You specify your own conditional constraints while saving data by using DynamoDBMapper with DynamoDBSaveExpression and these constraints failed.

Upvotes: 0

Janis Basis Basovs
Janis Basis Basovs

Reputation: 377

SOLUTION

An item with that ID allready exists in the Table.

You need to create a unique ID for the item you try to add.

Upvotes: 0

Suresh Kumar
Suresh Kumar

Reputation: 712

I received similar error.

The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: SMNKMSKJNSHBSGHVGHSB)

In my case I had not added sort key in my table and my second item had the same primary key as of first item. It worked after I added sort key.

Upvotes: 1

Peter Fennema
Peter Fennema

Reputation: 1690

Your goal is to save both records. There are 2 issues here

  1. With your choice of hash and range key it is impossible to save both records

The combination of hash and range key make a record unique. Event 1 and event 2 have the same values for hash and range key. Therefore the second put-item wil simply overwrite the first record.

  1. Your ConditionExpression prevents the replacement of record 1 by record 2

The ConditionExpression is evaluated just before putting a record. Your expression fails because when your event 2 is about to be inserted, DynamoDB discovers that a record with aggregateId “id1” already exists. The condition fails on "attribute_not_exists(aggregateId)", and you receive the ConditionalCheckFailedException This expression prevents overwriting of record 1 by record 2.

If you want to save both records you will have to come up with another choice of hash key and/or range key that better represents the unicity of your data item. You can not solve that with a ConditionExpression.

Upvotes: 28

Related Questions