1

I am creating a Infrastructure-as-Code for a Step Functions Machine. One of these states is of type 'Task' which performs a DynamoUpdateItem on a DynamoDB table.

The code looks as following:

    const updateDDB = new tasks.DynamoUpdateItem(this, 'Update item into DynamoDB', {
      key: { ['Task'] : tasks.DynamoAttributeValue.fromString('Processing') },
      table: table,
      updateExpression: 'SET LastRun = :label',
      expressionAttributeValues: {
        ':label.$': DynamoAttributeValue.fromString(JsonPath.stringAt('$$.Execution.StartTime')), 
      },
      resultPath: JsonPath.DISCARD,
    });

However, I keep getting an error saying the schema validation failed, and that

"The value for the field ':label.$' must be a STRING that contains a JSONPath but was an OBJECT at /States/Update item into DynamoDB/Parameters'"

How the heck is it not a string?!

I have tried writing it as [':label.$'], or even writing a .toString() function at the end of the JsonPath method

      expressionAttributeValues: {
        ':label.$': (DynamoAttributeValue.fromString(JsonPath.stringAt('$$.Execution.StartTime').toString())), 

      },

But nothing seems to work. I keep getting the same issue claiming that it's not a string.

Using something like JSON.stringify() doesn't work either because expressionAttributeValues takes a key and matches it with a DynamoAttributeValue.

fedonev
  • 20,327
  • 2
  • 25
  • 34
DevBob
  • 35
  • 4
  • I am not an expert on AWS, but the error does not say "must be a STRING". It says "must be a STRING that contains a JSONPath" which might suggest that you are indeed passing a string but it may not contain a JSONPath. But otherwise, it does claim you are passing an "OBJECT". But it could still be worth checking what the string says. – Tobias S. Jan 26 '23 at 13:23

1 Answers1

1

TL;DR Drop the .$ suffix from ':label.$': DynamoAttributeValue(...) in the expression attribute value definition. The key should be simply ':label'.


As @TobiasS says in the comments, the problem is with your State Machine task syntax. The .$ suffix on :label.$ tells AWS to expect a JSONPath string representing a path to a value. But a string is not valid State Machine syntax for this field. A key-value pair is required. The CDK docs have an example with the correct syntax.

❌ What your CDK code synthesizes to:

{
    "ExpressionAttributeValues": {
      ":label.$": { "S.$": "$$.Execution.StartTime" }
    },
}

✅ AWS expects the synthesized State Machine definition to be:

{
    "ExpressionAttributeValues": {
      ":label": { "S.$": "$$.Execution.StartTime" }
    },
}
fedonev
  • 20,327
  • 2
  • 25
  • 34
  • Thank you very much for taking the time to explain that. I tried what you proposed, and my CDK file did deploy. I am wondering however, will that perform the same action? See, I am using a Step Function Definition file and re-writing it into CDK Typescript. The original definition file had the code as ` "ExpressionAttributeValues": { ":label.$": "$$.Execution.StartTime" } ` but if I drop the .$, it results in a definition file that looks like this: ` "ExpressionAttributeValues": { ":label": { "S.$": "$$.Execution.StartTime" } }, – DevBob Jan 27 '23 at 16:55
  • @DevBob Glad to help. Yes, the answer produces [valid UpdateItem syntax](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html#DDB-UpdateItem-request-ExpressionAttributeValues). It produces the expected result when the State Machine is executed, something like `"LastRun": "2023-01-27T18:20:33.910Z"`. – fedonev Jan 27 '23 at 18:37