Boto 3 DynamoDB batchWriteItem Invalid attribute value type when specifying types
Question:
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?
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:
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'>
I was getting the same error message, but it ended up being a different issue. In my case, I was sending a BatchWriteItem
request, but had a request that looked like this:
"PutRequest": {
"Item": {
"Id": "5cc230c65d0948c0bcb5910cc9312e6a",
"Platform": "slack",
"SlackMessageId": None,
"SlackUserId": "U016H83F39V",
"SlackTeamId": "UTKUSRRSL&0",
"SlackOrgId": "TTKUSRQM6",
"Timestamp": Decimal("1618593370.910027027130126953125"),
"Selection": "yellow",
"Elaboration": "",
"Emotion": None,
"MeetingHours": None,
"PrivateElaboration": None,
"Reactions": None,
}
}
The issue is that according to the API documentation:
Attribute values must not be null; string and binary type attributes must have lengths greater than zero; and set type attributes must not be empty. Requests that contain empty values are rejected with a ValidationException exception.
The issue is the None
values, replacing them with non empty strings (i.e. 'null'
) solves the issue and lets the request go through! Hope this helps someone out.
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?
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:
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'>
I was getting the same error message, but it ended up being a different issue. In my case, I was sending a BatchWriteItem
request, but had a request that looked like this:
"PutRequest": {
"Item": {
"Id": "5cc230c65d0948c0bcb5910cc9312e6a",
"Platform": "slack",
"SlackMessageId": None,
"SlackUserId": "U016H83F39V",
"SlackTeamId": "UTKUSRRSL&0",
"SlackOrgId": "TTKUSRQM6",
"Timestamp": Decimal("1618593370.910027027130126953125"),
"Selection": "yellow",
"Elaboration": "",
"Emotion": None,
"MeetingHours": None,
"PrivateElaboration": None,
"Reactions": None,
}
}
The issue is that according to the API documentation:
Attribute values must not be null; string and binary type attributes must have lengths greater than zero; and set type attributes must not be empty. Requests that contain empty values are rejected with a ValidationException exception.
The issue is the None
values, replacing them with non empty strings (i.e. 'null'
) solves the issue and lets the request go through! Hope this helps someone out.