From 7911d73756c594b644497b60a9e04750a6e5d9b3 Mon Sep 17 00:00:00 2001 From: sanjrkmr Date: Fri, 18 Sep 2026 05:42:49 +0000 Subject: [PATCH 1/4] docs(cli): document replacements and unwedging in Express Mode Express Mode has rollback disabled by default, and CloudFormation does not perform replacement-type updates while rollback is disabled. Document that constraint next to the existing --no-rollback replacement note: how to deploy a replacing change (--express --rollback), why --rollback cannot rescue a stack that is already in UPDATE_FAILED, why cdk rollback is unavailable for express stacks, and how to unwedge such a stack by replaying the last successful configuration with --express --method=direct. Also notes why both flags are required for the replay, how to confirm up front that the replay really is a no-op, and that CloudFormation is expected to lift the restriction around 2026-11-15. Closes #1739 --- packages/aws-cdk/README.md | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 58017509d..2491883f0 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -285,6 +285,74 @@ a regular replacement instead. If the stack rollback is currently paused and you are trying to perform an deployment that contains a replacement, you will be prompted to roll back first. +#### Express Mode and resource replacements + +Express Mode (`cdk deploy --express`) has rollback disabled by default, and CloudFormation does not perform +replacement-type updates while rollback is disabled. CloudFormation classifies this as expected behavior, so this is a +documented constraint of deploying with rollback disabled. Express Mode supports resource replacements; it needs +rollback enabled to perform them. + +To deploy a change that replaces a resource in Express Mode, enable rollback for that deployment: + +```console +$ cdk deploy --express --rollback +``` + +This works on both the change set path and `--method=direct`. If the replacement is genuinely invalid, the deployment +fails with the underlying service error and CloudFormation rolls the stack back to a terminal state, rather than +leaving it stuck. + +If you deploy a replacing change with `--express` and rollback disabled, CloudFormation rejects the update with +`Replacement type updates not supported on stack with disable-rollback` and the stack is left in `UPDATE_FAILED`. +Adding `--rollback` at that point does not help, because `--express --rollback` cannot update a stack that is already +in a failed state: + +```console +ValidationError: This stack is currently in a non-terminal [UPDATE_FAILED] state. +``` + +`cdk rollback` does not help either, because CloudFormation does not offer `RollbackStack` for stacks last deployed +with Express Mode: + +```console +❌ MyStack failed: RollbackStack is not supported for stacks that were last updated using EXPRESS deployment mode and are in a failed state. To recover this stack, submit an UpdateStack request with the last known stable template. +Rollback failed (use --force to orphan failing resources) +``` + +The `use --force to orphan failing resources` hint does not apply here: `cdk rollback --force` fails identically. + +##### Unwedging a stack left in `UPDATE_FAILED` + +To return such a stack to a terminal state, replay the configuration that last deployed successfully: + +1. Revert your source so that your CDK app synthesizes the template that was last deployed successfully. +2. Run: + + ```console + $ cdk deploy --express --method=direct + ``` + +Both flags are required: + +- `--express`, because CloudFormation deployment mode is sticky: follow-up operations on the stack must stay in + `EXPRESS` mode until the stack reaches a `*_COMPLETE` state. +- `--method=direct`, because the change set path diffs against the template CloudFormation has already recorded — + which is the template you are replaying. That produces an empty diff, so the deployment reports `✅ (no changes)` and + exits 0 while the stack remains in `UPDATE_FAILED`. + +This *unwedges* the stack; it does not recover anything. The resource that failed already rolled itself back to its +previous revision, so the replay is a no-op that emits no resource events. **Your change is still not deployed.** +Re-apply it afterwards and deploy it with `cdk deploy --express --rollback`. + +Before replaying, confirm that the replay really will be a no-op: check that the failed resource reported +`UPDATE_ROLLBACK_COMPLETE` and is still at its previous revision (for an `AWS::ECS::TaskDefinition`, for example, the +live revision should still be the one from before the failed deployment). If it is, the replay changes nothing and +succeeds. If it is not, the replay is itself a replacement back to the earlier state and will fail in exactly the same +way, and you will need to deploy with rollback enabled instead. + +> CloudFormation is expected to lift this restriction for rollback-disabled deployments around 2026-11-15. Once that +> ships, replacements will work under `--express` without `--rollback` and this section no longer applies. + #### Deploying multiple stacks You can have multiple stacks in a cdk app. An example can be found in [how to create multiple stacks](https://docs.aws.amazon.com/cdk/latest/guide/stack_how_to_create_multiple_stacks.html). @@ -761,6 +829,12 @@ Some resources may fail to roll back. If they do, you can try again by calling `cdk rollback --force` to have the CDK CLI automatically orphan all failing resources. +`cdk rollback` is not available for stacks whose last deployment used Express Mode +(`cdk deploy --express`): CloudFormation does not support `RollbackStack` for those stacks while they are in +a failed state, and `--force` does not change that. See +[Express Mode and resource replacements](#express-mode-and-resource-replacements) for how to unwedge such a +stack. + (`cdk rollback` requires version 23 of the bootstrap stack, since it depends on new permissions necessary to call the appropriate CloudFormation APIs) From 3fda5efd974295d19a48664d8ae549d1601d7b93 Mon Sep 17 00:00:00 2001 From: sanjrkmr Date: Fri, 18 Sep 2026 20:30:09 +0000 Subject: [PATCH 2/4] docs(cli): do not publish a CloudFormation ECD in shipped docs Replace the dated expectation with an undated "until CloudFormation lifts this restriction". The date is another service team internal ECD and a stale-doc trap in a file we ship; it is kept in the code comment instead. --- packages/aws-cdk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 2491883f0..1a47139e0 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -350,8 +350,8 @@ live revision should still be the one from before the failed deployment). If it succeeds. If it is not, the replay is itself a replacement back to the earlier state and will fail in exactly the same way, and you will need to deploy with rollback enabled instead. -> CloudFormation is expected to lift this restriction for rollback-disabled deployments around 2026-11-15. Once that -> ships, replacements will work under `--express` without `--rollback` and this section no longer applies. +> This applies until CloudFormation lifts the restriction on replacements in rollback-disabled deployments. Once it +> does, replacements will work under `--express` without `--rollback` and this section no longer applies. #### Deploying multiple stacks From 774cab4cd6481e54dee9e2114e6e498f51b2bd12 Mon Sep 17 00:00:00 2001 From: sanjrkmr Date: Sun, 20 Sep 2026 05:31:32 +0000 Subject: [PATCH 3/4] docs(cli): correct the unwedge fallback, which pointed at an impossible command If the failed resource is already at a new revision, restoring the previous configuration is itself a replacement and CloudFormation refuses it for the same reason. The page told those users to "deploy with rollback enabled instead", which is the one operation that provably cannot update a stack already in UPDATE_FAILED - it answers ValidationError: non-terminal [UPDATE_FAILED] - so a stranded reader following it literally got a second error and no next step. Say plainly that there is no known redeploy recovery for that case, and point at delete/recreate or AWS Support. --- packages/aws-cdk/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 1a47139e0..f4e3d2ecd 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -347,8 +347,13 @@ Re-apply it afterwards and deploy it with `cdk deploy --express --rollback`. Before replaying, confirm that the replay really will be a no-op: check that the failed resource reported `UPDATE_ROLLBACK_COMPLETE` and is still at its previous revision (for an `AWS::ECS::TaskDefinition`, for example, the live revision should still be the one from before the failed deployment). If it is, the replay changes nothing and -succeeds. If it is not, the replay is itself a replacement back to the earlier state and will fail in exactly the same -way, and you will need to deploy with rollback enabled instead. +succeeds. + +If it is not — if the resource is already at a new revision — then restoring the previous configuration is itself a +replacement, and CloudFormation refuses it for the same reason. There is no known way to recover such a stack by +redeploying: `cdk deploy --express --rollback` cannot update a stack that is already in `UPDATE_FAILED`, and +`cdk rollback` is unavailable for Express Mode stacks. Delete and recreate the stack, or contact AWS Support if it +holds state you cannot afford to lose. > This applies until CloudFormation lifts the restriction on replacements in rollback-disabled deployments. Once it > does, replacements will work under `--express` without `--rollback` and this section no longer applies. From 6a07b83e36ca62d16599f5b9d19475d1a79498b0 Mon Sep 17 00:00:00 2001 From: sanjrkmr Date: Mon, 28 Sep 2026 04:49:18 +0000 Subject: [PATCH 4/4] docs(cli): cite CloudFormation for the replacement restriction, drop an undocumented status string --- packages/aws-cdk/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index f4e3d2ecd..5d7953e3b 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -288,9 +288,10 @@ will be prompted to roll back first. #### Express Mode and resource replacements Express Mode (`cdk deploy --express`) has rollback disabled by default, and CloudFormation does not perform -replacement-type updates while rollback is disabled. CloudFormation classifies this as expected behavior, so this is a -documented constraint of deploying with rollback disabled. Express Mode supports resource replacements; it needs -rollback enabled to perform them. +replacement-type updates while rollback is disabled. This is a documented constraint of deploying with rollback +disabled — [Stack failure options](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stack-failure-options.html#express-mode-and-rollback) +states that "disabling rollback isn't supported for immutable update operations". Express Mode supports resource +replacements; it needs rollback enabled to perform them. To deploy a change that replaces a resource in Express Mode, enable rollback for that deployment: @@ -344,10 +345,9 @@ This *unwedges* the stack; it does not recover anything. The resource that faile previous revision, so the replay is a no-op that emits no resource events. **Your change is still not deployed.** Re-apply it afterwards and deploy it with `cdk deploy --express --rollback`. -Before replaying, confirm that the replay really will be a no-op: check that the failed resource reported -`UPDATE_ROLLBACK_COMPLETE` and is still at its previous revision (for an `AWS::ECS::TaskDefinition`, for example, the -live revision should still be the one from before the failed deployment). If it is, the replay changes nothing and -succeeds. +Before replaying, confirm that the replay really will be a no-op: check that the failed resource is still at its +previous revision (for an `AWS::ECS::TaskDefinition`, for example, the live revision should still be the one from +before the failed deployment). If it is, the replay changes nothing and succeeds. If it is not — if the resource is already at a new revision — then restoring the previous configuration is itself a replacement, and CloudFormation refuses it for the same reason. There is no known way to recover such a stack by