Before opening, please complete the following steps:
Describe the bug
Found while migrating a small Gen 1 app (auth + storage + api + 2 functions, us-west-2) with amplify gen2-migration 14.5.1. The migration itself completed on 2026-09-21 once the CloudFormation ExecuteStackRefactor service issue was fixed; these two are tool defects that surfaced when the refactor step had to be re-run.
Defect 1: a failed refactor leaves a REVIEW_IN_PROGRESS holding stack that blocks every later run, and the automatic rollback then dies on it
When ExecuteStackRefactor fails on the first move (Gen 2 placeholder auth → <gen2-auth-stack>-holding), the refactor's CREATE STACK action has already created the holding stack in REVIEW_IN_PROGRESS with an empty template.
- Re-running
refactor then fails immediately because the tool treats the existing -holding stack as a conflict, and it cannot proceed past it.
- The tool's automatic rollback tries to update/delete that shell and fails with
Unable to find … / an empty-template error, so the run ends with a second failure on top of the first.
- Workaround we used: delete the
REVIEW_IN_PROGRESS shell by hand (aws cloudformation delete-stack), or pre-create the holding stacks (CREATE_COMPLETE, one AWS::CloudFormation::WaitConditionHandle) — the tool accepts pre-created holding stacks and then emits only MOVE actions.
Expected: the tool should detect a REVIEW_IN_PROGRESS holding stack from an earlier attempt and either delete/recreate it or reuse it, and the rollback path should tolerate an empty-template shell.
Defect 2: the plan phase leaves zero-change change sets on stacks it decides to skip
For stacks whose "prepare" step produces no template change (in our case the storage stacks on runs after the first), the plan phase still creates a change set, CloudFormation reports it as having no changes, and the tool leaves it in place (FAILED / "No updates are to be performed"). Several accumulate across retries and have to be deleted by hand.
Expected: delete the change set when it reports no changes (or skip creating it after a dry-run describe).
Suggestion: run DetectStackDrift as a pre-flight
While diagnosing the CloudFormation refusal we found the Gen 2 placeholder auth stack drifted (a hand edit to the placeholder app client) and the Gen 1 auth stack drifted (identity pool missing stack tags). Drift turned out not to be the trigger, but a moved resource with drift is a real risk for the refactor. A DetectStackDrift on every source/destination nested stack before the first CreateStackRefactor, failing fast on DRIFTED, would be a cheap safeguard.
Reproduction steps
- Gen 1 app locked; Gen 2 branch deployed with
ampx pipeline-deploy; amplify gen2-migration refactor --to <gen2-root>.
- Make the first
ExecuteStackRefactor fail (we hit the CloudFormation service issue, now fixed; any execute failure reproduces the shell).
- Observe
<gen2-auth-stack>-holding in REVIEW_IN_PROGRESS; observe the rollback error.
- Re-run the same command → rejected because of the holding stack.
- Observe leftover change sets on the storage stacks (
aws cloudformation list-change-sets).
Environment
@aws-amplify/cli 14.5.1, @aws-amplify/backend 1.18.x, Node 22, macOS
- Region us-west-2, account 170201464775 (details in the two support cases above)
Additional post-refactor findings (already passed to the service team via case 178914507800209, listed for completeness)
- Generated
auth/resource.ts omits UserPoolName / IdentityPoolName; after refactor the adopted pool has explicit names and UserPoolName is replacement-class, so postRefactor() needs to pin them (the generator already does this for the storage bucket name).
- An existing bucket policy on the adopted bucket makes the Step 8 deploy fail on the
AWS::S3::BucketPolicy re-create ("bucket policy already exists").
- The Gen 2 storage stack's
Custom::S3AutoDeleteObjects re-points at the adopted production bucket; the generated Retain override is the only guard.
Before opening, please complete the following steps:
amplify gen2-migration refactor --to <gen2-root-stack>Describe the bug
Found while migrating a small Gen 1 app (auth + storage + api + 2 functions, us-west-2) with
amplify gen2-migration14.5.1. The migration itself completed on 2026-09-21 once the CloudFormationExecuteStackRefactorservice issue was fixed; these two are tool defects that surfaced when the refactor step had to be re-run.Defect 1: a failed refactor leaves a
REVIEW_IN_PROGRESSholding stack that blocks every later run, and the automatic rollback then dies on itWhen
ExecuteStackRefactorfails on the first move (Gen 2 placeholder auth →<gen2-auth-stack>-holding), the refactor'sCREATE STACKaction has already created the holding stack inREVIEW_IN_PROGRESSwith an empty template.refactorthen fails immediately because the tool treats the existing-holdingstack as a conflict, and it cannot proceed past it.Unable to find …/ an empty-template error, so the run ends with a second failure on top of the first.REVIEW_IN_PROGRESSshell by hand (aws cloudformation delete-stack), or pre-create the holding stacks (CREATE_COMPLETE, oneAWS::CloudFormation::WaitConditionHandle) — the tool accepts pre-created holding stacks and then emits onlyMOVEactions.Expected: the tool should detect a
REVIEW_IN_PROGRESSholding stack from an earlier attempt and either delete/recreate it or reuse it, and the rollback path should tolerate an empty-template shell.Defect 2: the plan phase leaves zero-change change sets on stacks it decides to skip
For stacks whose "prepare" step produces no template change (in our case the storage stacks on runs after the first), the plan phase still creates a change set, CloudFormation reports it as having no changes, and the tool leaves it in place (
FAILED/ "No updates are to be performed"). Several accumulate across retries and have to be deleted by hand.Expected: delete the change set when it reports no changes (or skip creating it after a dry-run describe).
Suggestion: run
DetectStackDriftas a pre-flightWhile diagnosing the CloudFormation refusal we found the Gen 2 placeholder auth stack drifted (a hand edit to the placeholder app client) and the Gen 1 auth stack drifted (identity pool missing stack tags). Drift turned out not to be the trigger, but a moved resource with drift is a real risk for the refactor. A
DetectStackDrifton every source/destination nested stack before the firstCreateStackRefactor, failing fast onDRIFTED, would be a cheap safeguard.Reproduction steps
ampx pipeline-deploy;amplify gen2-migration refactor --to <gen2-root>.ExecuteStackRefactorfail (we hit the CloudFormation service issue, now fixed; any execute failure reproduces the shell).<gen2-auth-stack>-holdinginREVIEW_IN_PROGRESS; observe the rollback error.aws cloudformation list-change-sets).Environment
@aws-amplify/cli14.5.1,@aws-amplify/backend1.18.x, Node 22, macOSAdditional post-refactor findings (already passed to the service team via case 178914507800209, listed for completeness)
auth/resource.tsomitsUserPoolName/IdentityPoolName; after refactor the adopted pool has explicit names andUserPoolNameis replacement-class, sopostRefactor()needs to pin them (the generator already does this for the storage bucket name).AWS::S3::BucketPolicyre-create ("bucket policy already exists").Custom::S3AutoDeleteObjectsre-points at the adopted production bucket; the generatedRetainoverride is the only guard.