diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 626dcce5c57e7..86d1dc4828e1d 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -440,6 +440,12 @@ async function canSkipDeploy( return false; } + // Existing stack is in a failed state + if (cloudFormationStack.stackStatus.isFailure) { + debug(`${deployName}: stack is in a failure state`); + return false; + } + // We can skip deploy return true; } diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index 6e45a20acc770..9f061a2214d13 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -423,6 +423,27 @@ test('deploy not skipped if template did not change but one tag removed', async expect(cfnMocks.getTemplate).toHaveBeenCalledWith({ StackName: 'withouterrors', TemplateStage: 'Original' }); }); +test('deploy is not skipped if stack is in a _FAILED state', async () => { + // GIVEN + givenTemplateIs(FAKE_STACK.template); + givenStackExists({ + StackStatus: 'DELETE_FAILED', + }); + + // WHEN + let err; + await deployStack({ + stack: FAKE_STACK, + sdk, + sdkProvider, + resolvedEnvironment: mockResolvedEnvironment(), + usePreviousParameters: true, + }).catch(e => err = e); + + // THEN + expect(err).toEqual(Error('The stack named withouterrors failed to deploy: DELETE_FAILED')); +}); + test('existing stack in UPDATE_ROLLBACK_COMPLETE state can be updated', async () => { // GIVEN givenStackExists(