Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boto 3 DynamoDB batchWriteItem Invalid attribute value type when specifying types

I have a strange problem with Python Boto3 when trying to do a batch_write_item to a DynamoDB table. I am following the documentation and trying to write a singe item. The table is setup correctly and I can run batch-write-item via the AWS cli no problem.

Assuming the client and DynamoDB are set up correctly I run:

client.batch_write_item(RequestItems={
    "myTable": [
        {
            "PutRequest": {
                "Item": {
                    "name": {
                        "S": "hello"
                    },
                    "value": {
                        "S": "world"
                    }
                }
            }
        }
    ]
})

I get the following error:

botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the BatchWriteItem operation: Invalid attribute value type

If I change it, removing the types and run:

client.batch_write_item(RequestItems={
    "myTable": [
        {
            "PutRequest": {
                "Item": {
                    "name": "hello",
                    "value": "world"
                }
            }
        }
    ]
})

It works as expected.

I need to use the previous format which follows the documentation and is compatibale with AWS cli.

Is the documentation wrong or I missed a configuration setting, version issue or something else?

like image 282
Jeff S. Avatar asked Jan 22 '18 01:01

Jeff S.


People also ask

What are the examples of DynamoDB boto3 query?

List of DynamoDB Boto3 Query Examples 1 Connecting Boto3 to DynamoDB 2 Create Table 3 Get All Items / Scan 4 Get Item 5 Batch Get Item 6 Put Item 7 Query Set of Items 8 Update Item 9 Conditionally Update Item 10 Increment Item Attribute 11 Delete Item 12 Delete All Items 13 Query with Sorting 14 Query Pagination 15 Run DynamoDB Local More ...

What is batchwriteitem in DynamoDB?

With BatchWriteItem, you can efficiently write or delete large amounts of data, such as from Amazon EMR, or copy data from another database into DynamoDB. In order to improve performance with these large-scale operations, BatchWriteItem does not behave in the same way as individual PutItem and DeleteItem calls would.

How do I put an item in DynamoDB?

Boto3 Put Item To write a single item into the DynamoDB Table, use PutItem operation: import boto3 dynamodb = boto3.resource('dynamodb', region_name=region) table = dynamodb.Table('my-table') response = table.put_item( Item={ 'id': 1, 'title': 'my-document-title', 'content': 'some-content', } )

How do I restrict the update logic in boto3?

Boto3 Conditionally Update Item Moreover, you can also add a ConditionExpression parameter, which restricts the update logic only if the evaluated expression equals true. import boto3 dynamodb = boto3. resource ('dynamodb', region_name = region) table = dynamodb.


1 Answers

This just got me as well, looks like you're using a DynamoDB resource, not a client. They both provide the same function but it acts very slightly differently. Here's what you're looking for:

http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.ServiceResource.batch_write_item

That aside, the docs are still pretty unclear. Here's what I found:

  • When using a resource (what you're currently doing), you may specify the type of non-key attributes, and you must not specify the type of key attributes
  • When using a client (the other option), you must specify the type of all attributes.

Using the DynamoDB resource:

resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')

mytable = resource.create_table(
    TableName='mytable',
    KeySchema=[{ 'AttributeName': 'name', 'KeyType': 'HASH' }],
    AttributeDefinitions=[{ 'AttributeName': 'name', 'AttributeType': 'S' }],
    ProvisionedThroughput={ 'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5 }
)

try:
    resource.batch_write_item(RequestItems={
        'mytable': [{ 'PutRequest': { 'Item': {
            'name': { 'S': 'myname' },
            'value': { 'S': 'myvalue' }
        }}}]
    })
    print(f'resource, specify all types : write succeeded.')
except Exception as e:
    print(f'resource, specify all types : write failed: {e}')

try:
    resource.batch_write_item(RequestItems={
        'mytable': [{ 'PutRequest': { 'Item': {
            'name': 'myname',
            'value': { 'S': 'myvalue' }
        }}}]
    })
    print(f'resource, specify value only: write succeeded.')
except Exception as e:
    print(f'resource, specify value only: write failed: {e}')

try:
    resource.batch_write_item(RequestItems={
        'mytable': [{ 'PutRequest': { 'Item': {
            'name': 'myname',
            'value': 'myvalue'
        }}}]
    })
    print(f'resource, specify none      : write succeeded.')
except Exception as e:
    print(f'resource, specify none      : write failed: {e}')

Output

resource, specify all types : write failed:
    An error occurred (ValidationException) when calling the BatchWriteItem operation: Invalid attribute value type
resource, specify value only: write succeeded.
resource, specify none      : write succeeded.

And then using the DynamoDB client (replace all "resource"s above with client)

client = boto3.client('dynamodb', endpoint_url='http://localhost:8000')
try:
    client.batch_write_item(RequestItems={    
....

Output

client, specify all types : write succeeded.
client, specify value only: write failed: Parameter validation failed:
    Invalid type for parameter RequestItems.mytable[0].PutRequest.Item.name, value: myname, type: <class 'str'>, valid types: <class 'dict'>
client, specify none      : write failed: Parameter validation failed:
    Invalid type for parameter RequestItems.mytable[0].PutRequest.Item.name, value: myname, type: <class 'str'>, valid types: <class 'dict'>
    Invalid type for parameter RequestItems.mytable[0].PutRequest.Item.value, value: myvalue, type: <class 'str'>, valid types: <class 'dict'>
like image 63
Thomas Steinke Avatar answered Nov 01 '22 19:11

Thomas Steinke