Logo

[Cloudformation] Deploying Cloudformation Change Sets without InvalidChangeSetStatus Error

GHA

The Error I Hit

I got this error during a CloudFormation deployment via GitHub Actions:

1An error occurred (InvalidChangeSetStatus) when calling the ExecuteChangeSet operation:
2ChangeSet [...] cannot be executed in its current status of [CREATE_IN_PROGRESS]

The execute-change-set step was trying to run before the change set was fully created. Classic timing issue.

The Fix

I added a simple polling step to wait for the change set to reach CREATE_COMPLETE before executing it. If the status becomes FAILED, it prints out the error and exits.

1- name: Wait for change set to be created
2 run: |
3 for i in {{1..30}}; do
4 status=$(aws cloudformation describe-change-set
5 --change-set-name "${{ steps.generate-stack-name.outputs.change_set_name }}"
6 --stack-name "${{ env.STACK_NAME }}"
7 --query "Status" --output text)
8
9 echo "Current change set status: $status"
10
11 if [[ "$status" == "CREATE_COMPLETE" ]]; then
12 break
13 elif [[ "$status" == "FAILED" ]]; then
14 echo "ERROR: Change set creation failed." >&2
15 aws cloudformation describe-change-set
16 --change-set-name "${{ steps.generate-stack-name.outputs.change_set_name }}"
17 --stack-name "${{ env.STACK_NAME }}"
18 exit 1
19 fi
20
21 echo "Waiting 10s for change set to be ready..."
22 sleep 10
23 done

When It Happens

This happens because create-change-set is asynchronous β€” it returns instantly while still processing in the background. If you try to execute it right away, CloudFormation throws an error.

The Full Code

1runs-on: ubuntu-latest
2 steps:
3 - name: Checkout
4 uses: actions/checkout@v4
5
6 - name: Configure AWS credentials
7 uses: aws-actions/configure-aws-credentials@v4
8 with:
9 role-to-assume: ${{ env.AWS_ROLE }}
10 aws-region: ${{ env.AWS_REGION }}
11
12 - name: Generate change set name
13 id: generate-stack-name
14 run: |
15 TIMESTAMP=$(date '+%Y%m%d-%H%M%S')
16 echo "timestamp=$TIMESTAMP" >> "$GITHUB_OUTPUT"
17 echo "change_set_name=${STACK_NAME}-$TIMESTAMP" >> "$GITHUB_OUTPUT"
18
19 - name: Upload template to S3
20 run: |
21 aws s3 cp $TEMPLATE_FILE s3://${{ env.S3_BUCKET }}/${{ github.sha }}.yaml
22
23 - name: Create CloudFormation change set
24 run: |
25 aws cloudformation create-change-set \
26 --stack-name "${{ env.STACK_NAME }}" \
27 --template-url https://s3.amazonaws.com/${{ env.S3_BUCKET }}/${{ github.sha }}.yaml \
28 --change-set-name "${{ steps.generate-stack-name.outputs.change_set_name }}" \
29 --capabilities CAPABILITY_NAMED_IAM
30
31 - name: Wait for change set to be created
32 run: |
33 for i in {1..30}; do
34 status=$(aws cloudformation describe-change-set \
35 --change-set-name "${{ steps.generate-stack-name.outputs.change_set_name }}" \
36 --stack-name "${{ env.STACK_NAME }}" \
37 --query "Status" --output text)
38
39 echo "Current change set status: $status"
40
41 if [[ "$status" == "CREATE_COMPLETE" ]]; then
42 break
43 elif [[ "$status" == "FAILED" ]]; then
44 echo "ERROR: Change set creation failed." >&2
45 aws cloudformation describe-change-set \
46 --change-set-name "${{ steps.generate-stack-name.outputs.change_set_name }}" \
47 --stack-name "${{ env.STACK_NAME }}"
48 exit 1
49 fi
50
51 echo "Waiting 10s for change set to be ready..."
52 sleep 10
53 done
54
55 - name: Execute CloudFormation change set
56 run: |
57 aws cloudformation execute-change-set \
58 --change-set-name "${{ steps.generate-stack-name.outputs.change_set_name }}" \
59 --stack-name "${{ env.STACK_NAME }}"

Pro Tip

Always check the change set status before execution. I had no idea at first that GitHub Actions could try to execute it mid-creation.

This fix helped make my deploys stable and smooth.

If you're also automating CloudFormation updates via GitHub Actions, definitely consider waiting before the execution step. It’s a small addition but saved me a lot of debugging time πŸ”§πŸš€