aws / aws/aws-cdk

(aws-stepfunctions-tasks): DynamoAttributeValue.fromNumber() breaks when passed a JsonPath

Open
#12,456 11 comments 17 reactions 0 assignees View on GitHub
@aws-cdk/aws-stepfunctions-tasks bug effort/medium p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

`DynamoAttributeValue.fromNumber()` synths incorrectly when passed a `JsonPath.numberAt()` for getting a number from a step's input.

Example:

```ts
DynamoAttributeValue.fromNumber(JsonPath.numberAt('$.viewCount')
```

Synths as:

```
{\":viewCount\":{\"N\":\"-1.888154589708819e+289\"}}
```

### Reproduction Steps

#### 1. Deploy ProblemStack

```ts
import { Table, AttributeType, BillingMode } from '@aws-cdk/aws-dynamodb';
import { LogGroup, RetentionDays } from '@aws-cdk/aws-logs';
import { StateMachine, Chain, StateMachineType, LogLevel, JsonPath } from '@aws-cdk/aws-stepfunctions';
import { DynamoUpdateItem, DynamoAttributeValue, DynamoReturnValues } from '@aws-cdk/aws-stepfunctions-tasks';
import { Stack, Construct, StackProps, RemovalPolicy } from '@aws-cdk/core';

export class ProblemStack extends Stack {

constructor(scope: Construct, id: string, props: StackProps = {}) {
super(scope, id, props);

const table = new Table(this, 'MyTable', {
partitionKey: { name: 'id', type: AttributeType.STRING },
billingMode: BillingMode.PAY_PER_REQUEST,
removalPolicy: RemovalPolicy.DESTROY,
});

const updateViewCount = new DynamoUpdateItem(this, 'PutVideosViewCount', {
table: table,
key: {
id: DynamoAttributeValue.fromString(JsonPath.stringAt('$.id')),
},
returnValues: DynamoReturnValues.ALL_NEW,
updateExpression: 'SET viewCount = :viewCount',
expressionAttributeValues: {
':viewCount': DynamoAttributeValue.fromNumber(JsonPath.numberAt('$.viewCount')),
},
});

const main = Chain.start(updateViewCount);

const stateMachineLogs = new LogGroup(this, 'MyStateMachineLogGroup', {
retention: RetentionDays.THREE_MONTHS,
});

new StateMachine(this, 'MyStateMachine', {
definition: main,
stateMachineType: StateMachineType.STANDARD,
tracingEnabled: true,
logs: {
destination: stateMachineLogs,
includeExecutionData: true,
level: LogLevel.ALL,
},
});
}
}
```

#### 2. Insert a record into the DynamoDB table

```json
{
"id": "foo",
"viewCount": 10
}
```

#### 3. Start state machine execution with event

```json
{
"id": "foo",
"viewCount": 1234
}
```

### What did you expect to happen?

The template should synth to extract the number from the input and then update the record in the db.

### What actually happened?

The execution fails with the error:

```
"ExpressionAttributeValues contains invalid value: Number overflow. Attempting to store a number with magnitude larger than supported range for key :viewCount (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: c056d945-3aa5-484e-8c64-eb75b9b9041c; Proxy: null)
```

This is because the template was synthed as:

```
\"ExpressionAttributeValues\":{\":viewCount\":{\"N\":\"-1.888154589708819e+289\"}}
```

### Environment

- **CDK CLI Version :** 1.83.0
- **Framework Version:**
- **Node.js Version:** v12.19.0
- **OS :** Linux
- **Language (Version):** TypeScript Version 4.0.5

### Other

---

This is :bug: Bug Report

Contributor guide

Open the contributing guide

Research direction

Trace DynamoAttributeValue.fromNumber() and JsonPath.numberAt() in the aws-stepfunctions-tasks implementation, then find the related synthesis or task tests. Reproduce the supplied stack and verify that a JsonPath number produces a valid runtime DynamoDB value instead of a huge literal and that the update succeeds.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
backend, cloud
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.