rds: RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE not propagated to child resources in RDS constructs
#37780 opened on May 6, 2026
Description
Describe the bug
When RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE is set on DatabaseCluster, DatabaseInstance, or
ServerlessCluster, the helper resources they create (subnet groups and instances) do not
inherit the policy. They are silently left with CloudFormation's default Delete behavior, meaning
they will attempt to be destroyed on stack deletion but usually fail because they are in use.
Affected Constructs
aws-cdk-lib/aws-rds.DatabaseClusterNewaws-cdk-lib/aws-rds.DatabaseInstanceNewaws-cdk-lib/aws-rds.ServerlessClusterNew
##Root Cause
Found three references in RDS that compare removal policies against RemovalPolicy.RETAIN only, missing RETAIN_ON_UPDATE_OR_DELETE which was added later.
- helperRemovalPolicy in aws-rds/lib/private/util.ts
This function determines the policy applied to helper resources (subnet groups, cluster instances). It predates RETAIN_ON_UPDATE_OR_DELETE and only handles RETAIN: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-rds/lib/private/util.ts#L151
export function helperRemovalPolicy(basePolicy?: RemovalPolicy): RemovalPolicy {
return basePolicy === RemovalPolicy.RETAIN
? RemovalPolicy.RETAIN
: RemovalPolicy.DESTROY;
}
RETAIN_ON_UPDATE_OR_DELETE falls through to DESTROY, which is then suppressed by renderUnless, resulting in undefined being passed to SubnetGroup — so no policy is applied at all.
- defaultDeletionProtection in aws-rds/lib/private/util.ts
Deletion protection is not auto-enabled when removalPolicy is RETAIN_ON_UPDATE_OR_DELETE, even though it is for RETAIN: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-rds/lib/private/util.ts#L83
return deletionProtection ?? (removalPolicy === RemovalPolicy.RETAIN ? true : undefined);
- ServerlessClusterNew subnet group in aws-rds/lib/serverless-cluster.ts
An inline check independent of helperRemovalPolicy has the same problem: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-rds/lib/serverless-cluster.ts#L475
removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined,
Regression Issue
- Select this option if this issue appears to be a regression.
Last Known Working CDK Library Version
RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE was introduced in aws/aws-cdk#26602.
Expected Behavior
"Postgres2V17ClusterSubnets001BC406": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"DBSubnetGroupDescription": "Subnets for Cluster database",
"SubnetIds": [
"subnet-0123",
"subnet-01234",
"subnet-012345"
],
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "RetainExceptOnCreate",
"Metadata": {
"aws:cdk:path": "Postgres2V17/Cluster/Subnets/Default"
}
},
Current Behavior
"Postgres2V17ClusterSubnets001BC406": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"DBSubnetGroupDescription": "Subnets for Cluster database",
"SubnetIds": [
"subnet-0123",
"subnet-01234",
"subnet-012345"
],
},
"Metadata": {
"aws:cdk:path": "Postgres2V17/Cluster/Subnets/Default"
}
},
Reproduction Steps
const cluster = new rds.DatabaseCluster(stack, 'Cluster', {
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_17_2,
}),
vpc,
removalPolicy: cdk.RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE,
});
Possible Solution
helperRemovalPolicy — pass RETAIN_ON_UPDATE_OR_DELETE through rather than collapsing it to RETAIN. Helper resources are created before the primary resource, so if their creation fails and the stack rolls back, RetainExceptOnCreate correctly allows them to be cleaned up rather than orphaned:
export function helperRemovalPolicy(basePolicy?: RemovalPolicy): RemovalPolicy {
return basePolicy === RemovalPolicy.RETAIN || basePolicy ===
RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE
? basePolicy
: RemovalPolicy.DESTROY;
}
defaultDeletionProtection — extend the condition:
return deletionProtection ?? (
removalPolicy === RemovalPolicy.RETAIN || removalPolicy === RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE
? true
: undefined
);
serverless-cluster.ts — replace the inline check with renderUnless and helperRemovalPolicyto stay consistent with DatabaseCluster and DatabaseInstance:
removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY),
Additional Information/Context
No response
AWS CDK Library version (aws-cdk-lib)
2.240.0
AWS CDK CLI version
2.1108.0 (build eace286)
Node.js Version
v22.19.0
OS
macOS Tahoe 26.4.1 (25E253)
Language
TypeScript
Language Version
No response
Other information
No response