ValidationError on calling ListStacks on AWS Cloudformation

Viewed 216

I have a piece of python code that calls the ListStacks action on AWS's Cloudformation API:

client = boto3.client('cloudformation', region_name='[MYREGION]')

status_filter = ['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'ROLLBACK_COMPLETE']  

response = client.list_stacks(StackStatusFilter=status_filter)

next_token = response.get('NextToken', None)

while next_token:
    response = client.list_stacks(NextToken=next_token)

On the last line, it throws a ValidationError:

An error occurred (ValidationError) when calling the ListStacks operation: [TOKEN] is not a valid NextToken

This has been working fine for month, but now it suddenly throws this error. There has been no changes to the code.

Curiously, the response is smaller than 1MB, so the token should be null, according to the documentation:

NextToken
If the output exceeds 1 MB in size, a string that identifies the next page of stacks.
If no additional page exists, this value is null.
Type: String
Length Constraints: Minimum length of 1. Maximum length of 1024

Does anyone have an idea why the response contains an (invalid) NextToken rather than null?

Edit

My assumption that the response was not exceeding the limit was wrong. It did only return a subset of the stacks fitting the filter.

So the question is rather: Why is the NextToken invalid?

2 Answers

I could not figure out why the NextToken is invalid, but a colleague pointed out that we can circumvent the problem by using the Cloudformation.Paginator.ListStacks class.

client = boto3.client('cloudformation', region_name='eu-central-1')
paginator = client.get_paginator('list_stacks')
status_filter = ['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'ROLLBACK_COMPLETE']

response_iterator = paginator.paginate(
  StackStatusFilter=status_filter
)
stacks = []
for response in response_iterator:
  stacks += [stack['StackName'] for stack in response['StackSummaries']]

return stacks

I was seeing the same error with this code:

            for region in get_regions(aws):
                instances = cf_client.list_stack_instances(StackSetName=data[i]['StackSetId'],region_name=region['RegionName'])
                stack_instances.append(instances)
                while 'NextToken' in instances:
                    more_instances = cf_client.list_stack_instances(
                        StackSetName=data[i]['StackSetName'],
                        NextToken=instances['NextToken'],
                        MaxResults=99,
                        StackInstanceRegion=region['RegionName']
                    )

After trying both the paginator and some other ideas, I simplified the function parameters when stepping through my code by removing the StackInstanceRegion and MaxResults, e.g.

while 'NextToken' in instances:
                    more_instances = cf_client.list_stack_instances(
                        StackSetName=data[i]['StackSetName'],
                        NextToken=instances['NextToken']
                    )

And now it's working with client.list_stack_instances()

Related