Skip to content

[aws-stepfunctions]: Nested arrays are not serialized correctly on input #14599

@marciocarmona

Description

@marciocarmona

If part of a Step Function task contains a nested array, part of the array is serialized as an object with the indexes as their string keys.

The issue seems to be inside the TaskInput.fromObject call, more specifically in the recurseArray calls.

Reproduction Steps

        let test = {
            x: [["Hello", "world"], ["this", "is", "bugged"]]
        }

        console.log(util.inspect(renderObject(test), {showHidden: false, depth: null}))

What did you expect to happen?

This should have been returned:

{
  x: [
    ['Hello', 'world'],
    ['this', 'is', 'bugged']
  ]
}

What actually happened?

It returned this:

{
  x: [
    { '0': 'Hello', '1': 'world' },
    { '0': 'this', '1': 'is', '2': 'bugged' }
  ]
}

Environment

  • CDK CLI Version : 1.98.0 (build 79f4512)
  • Framework Version: ?
  • Node.js Version: v12.22.1
  • OS : Linux Red Hat 7.2.1-2
  • Language (Version): TypeScript (4.0.5)

Other

After doing some research I noticed that for deeply nested arrays, every other array ends up mapped to an object. e.g.

        let test = {
            x: [[[[[[[[[[["Hi!"]]]]]]]]]]]
        }

        console.log(util.inspect(renderObject(test), {showHidden: false, depth: null}))

Output:

{
  x: [
    {
      '0': [
        {
          '0': [
            {
              '0': [
                {
                  '0': [ { '0': [ 'Hi!' ] } ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

The problem seems to come from this recurseArray method:

function recurseArray(key: string, arr: any[], handlers: FieldHandlers, visited: object[] = []): {[key: string]: any[] | string} {
if (isStringArray(arr)) {
const path = jsonPathStringList(arr);
if (path !== undefined) {
return handlers.handleList(key, arr);
}
// Fall through to correctly reject encoded strings inside an array.
// They cannot be represented because there is no key to append a '.$' to.
}
return {
[key]: arr.map(value => {
if ((typeof value === 'string' && jsonPathString(value) !== undefined)
|| (typeof value === 'number' && jsonPathNumber(value) !== undefined)
|| (isStringArray(value) && jsonPathStringList(value) !== undefined)) {
throw new Error('Cannot use JsonPath fields in an array, they must be used in objects');
}
if (typeof value === 'object' && value !== null) {
return recurseObject(value, handlers, visited);
}
return value;
}),
};
}

Notice that it checks if value is an object before checking if it's an array, since arrays are actually considered objects by Javascript, it ends up calling the recurseObject method.

Recommendation:

  • Check if value is an array first and call the recurseArray method instead.

This is 🐛 Bug Report

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-stepfunctionsRelated to AWS StepFunctionsbugThis issue is a bug.closed-for-stalenessThis issue was automatically closed because it hadn't received any attention in a while.effort/smallSmall work item – less than a day of effortp1

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions