Search code examples
node.jsaws-lambdaamazon-dynamodb

AWS DynamoDB update item command gets ValidationException: The provided key element does not match the schema


Given the table with user_id (partition key) and created_at (sort key):

{
  "user_id": {
    "S": "..."
  },
  "created_at": {
    "N": "...."
  },
  "bot_answer": {
    "S": "..."
  },
  "question": {
    "S": "..."
  }
}

My lambda receives the insert event from dynamodb:

{
    "Records": [
        {
            ....
            "eventName": "INSERT",
            ....
            "dynamodb": {
                ....
                "Keys": {
                    "user_id": {
                        "S": "user123"
                    },
                    "created_at": {
                        "N": "1681218896790"
                    }
                },
                "NewImage": {
                    "question": {
                        "S": "What is the capital of USA?"
                    },
                    "user_id": {
                        "S": "user123"
                    },
                    "created_at": {
                        "N": "1681218896790"
                    },
                    "bot_answer": {
                        "S": ""
                    }
                },
                .....
                "StreamViewType": "NEW_AND_OLD_IMAGES"
            },
            ......
        }
    ]
}

I try to update an item with the command (from execution logs):

{
  TableName: 'chat_messages_tbl',
  Key: { 
   user_id: { S: 'user123' }, 
   created_at: { N: '1681218896790' } 
  },
  UpdateExpression: 'SET bot_answer = :bot_answer',
  ExpressionAttributeValues: { ':bot_answer': { S: 'Hello from bot!' } },
  ReturnValues: 'UPDATED_NEW'
}

But I get the ValidationException: The provided key element does not match the schema

// sample code from lambda (nodejs)

const dynamoDB = DynamoDBDocumentClient.from(dynamoDBClient)
const result = await dynamoDB.send(new UpdateCommand({
  TableName: 'chat_messages_tbl',
  Key: { 
   user_id: { S: 'user123' }, 
   created_at: { N: '1681218896790' } 
  },
  UpdateExpression: 'SET bot_answer = :bot_answer',
  ExpressionAttributeValues: { ':bot_answer': { S: 'Hello from bot!' } },
  ReturnValues: 'UPDATED_NEW'
}))

NOTE since the created_at is a number, I also tried to send it in the update command without single quotes:

created_at: { N: 1681218896790 }  // instead of { N : '1681218896790' } 

Thanks, F.


Solution

  • when using DynamoDBDocumentClient, you should use native JavaScript types rather than the DynamoDB JSON format and also remove the S and N from the keys and pass the values as native types.

    example:

    const dynamoDB = DynamoDBDocumentClient.from(dynamoDBClient);
    const result = await dynamoDB.send(new UpdateCommand({
      TableName: 'chat_messages_tbl',
      Key: { 
        user_id: 'user123',  // No need to wrap in { S: '...' }
        created_at: 1681218896790  // Pass as a JavaScript number, not as { N: '...' }
      },
      UpdateExpression: 'SET bot_answer = :bot_answer',
      ExpressionAttributeValues: { ':bot_answer': 'Hello from bot!' },  // No need to wrap in { S: '...' }
      ReturnValues: 'UPDATED_NEW'
    }));