"The document path provided in the update expression is invalid for update" when trying to update a map value

Viewed 1676

Here is my sample code

import boto3

import os

ENV = "dev"
DB = "http://awsservice.com"
REGION = "us-east-1"
TABLE = "traffic-count"


def main():
    os.environ["AWS_PROFILE"] = ENV
    client = boto3.resource("dynamodb", endpoint_url=DB, region_name=REGION)

    kwargs = {'Key': {'id': 'D-D0000012345-P-1'}, 
            'UpdateExpression': 'ADD #count.#car  :delta \n            SET #parentKey = :parent_key, #objectKey = :object_key', 
            'ExpressionAttributeValues': {':delta': 1, ':parent_key': 'District-D0000012345', ':object_key': 'Street-1'}, 
            'ExpressionAttributeNames': {'#car': 'car', '#count': 'count', '#parentKey': 'parentKey', '#objectKey': 'objectKey'}}

    client.Table(TABLE).update_item(**kwargs)


if __name__ == "__main__":
    main()

What I want to achieve is this:

With a single API call (in this update_item), I want to be able to

  1. If the item does not exit. create an item with a map count and initialise it with {'car': 1} and set the fields parent_key and object_key.

or

  1. If the item already exists, update the field to {'car': 2} (if the original count is 1)

Previously, if I did not use a map, I can successfully update with this expression,

SET #count = if_not_exist(#count, :zero) +  :delta, 
    #parentKey = :parent_key, #objectKey = :object_key

However I am getting this error:

botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the UpdateItem operation: The document path provided in the update expression is invalid for update

Which document path is causing the problem? How can I fix it?

1 Answers

For those who landed on this page with similar error:

The document path provided in the update expression is invalid for update

The reason may be:

for the item on which the operation is being performed, 
this attribute (count, for example) is not yet set.

Considering the sample code from question, The exception could be coming from all those items where count is empty or not set. So the update query doesn't know on which map the new value(s) (car, for example) needs to be set or updated.

In the question, it was possible for the OP in the beginning because, the attribute is not a map and the process is simply setting the value to count as is. It's not trying to access a key of an unknown map to set the value.

This can be handled by catching the exception. For example:

from botocore.exceptions import ClientError
...
try:
    response = table.update_item(
        Key={
            "pk": pk
        },
        UpdateExpression="set count.car = :c,
        ExpressionAttributeValues={
            ':c': "some car"
        },
        ReturnValues="UPDATED_NEW"
    )
except ClientError as e:
    if e.response['Error']['Code'] == 'ValidationException':
        response = table.update_item(
            Key={
                "pk": pk
            },
            UpdateExpression="set count = :count",
            ExpressionAttributeValues={
                ':count': {
                    ':c': "some car"
                }
            },
            ReturnValues="UPDATED_NEW"
        )
Related