Describe the bug
cdk import fails on any stack whose deployed template contains a non-ASCII character in a resource property, even when the local code is byte-identical to what is actually deployed.
Root cause: cdk import builds its import template from the deployed template (CloudFormation GetTemplate) plus the resources being imported. GetTemplate is lossy — it replaces non-ASCII characters with a literal ASCII ?. CDK therefore submits a template in which an untouched resource's property differs from what CloudFormation actually holds, and CloudFormation rejects the IMPORT change set:
You have modified resources [<LogicalId>] in your template that are not being imported.
Update, create or delete operations cannot be executed during import operations.
The named resource has not been modified by the user at all — the only difference is — (U+2014) vs ?.
This is the same CloudFormation mangling already known to cdk diff, which has masked it since aws/aws-cdk#25912 ("Omitted N changes because they are likely mangled non-ASCII characters. Use --strict to print them."). That masking was never applied to the cdk import code path, so the problem is invisible in cdk diff and then blocks cdk import with an error that points at an innocent resource.
The affected property in our case is AWS::IAM::ManagedPolicy.Description, which is create-only — so it cannot be "fixed" in place to work around the issue. Changing it forces a replacement, and since ManagedPolicyName is also create-only and fixed, replacement fails with EntityAlreadyExists. Affected users have no remediation path within CDK.
Expected Behavior
cdk import succeeds. A property whose deployed value differs from the local value only by GetTemplate's non-ASCII mangling should be treated as unchanged — the same way cdk diff has treated it since aws/aws-cdk#25912.
Current Behavior
cdk import fails during change-set creation:
MyFoundationStack: creating CloudFormation changeset...
❌ MyFoundationStack failed: CloudFormationServiceException [ValidationError]:
You have modified resources [MyScopedPolicy1A2B3C4D] in your template that are not
being imported. Update, create or delete operations cannot be executed during import operations.
Verification that the resource is genuinely unmodified:
- Local synthesized template:
"Description": "Scoped IAM access for the app production role — App resources only." (U+2014)
aws iam get-policy: returns the same string, with U+2014 intact — the live resource is correct
aws cloudformation get-template: returns "Scoped IAM access for the app production role ? App resources only." (?, 0x3F)
cdk diff reports no change to this resource, printing only Omitted 1 changes because they are likely mangled non-ASCII characters.
Editing the local source to contain a literal ? does not help — the published import template is byte-identical either way, since the local source is not an input to it. That is what pinned the cause to the GetTemplate round-trip.
Reproduction Steps
-
Synthesize a stack containing a resource with a non-ASCII character in a string property, e.g.:
new iam.ManagedPolicy(this, 'Policy', {
managedPolicyName: 'my-policy',
description: 'Scoped access — resources only.', // U+2014 EM DASH
statements: [ /* ... */ ],
});
-
cdk deploy.
-
aws cloudformation get-template --stack-name <stack> — the description comes back with ? instead of —.
-
Add to the same stack a resource that already exists in the account and is intended for import (any importable type; we used an AWS::SNS::Topic plus its AWS::SNS::Subscription).
-
cdk import <stack> and supply the physical identifier when prompted.
-
Change-set creation fails with the ValidationError above, naming the policy — a resource not involved in the import.
Possible Solution
Apply the mangling-aware comparison introduced in aws/aws-cdk#25912 to the import path: when building the import template, treat a deployed value that is the mangled form of the local value as unchanged. Alternatively, construct the import template from the synthesized template (which retains the true characters) rather than from GetTemplate output.
Workaround for anyone hitting this: bypass cdk import and submit the change set directly, using the synthesized template as the base, so the true characters reach CloudFormation.
aws s3 cp import-template.json s3://<bucket>/import-template.json
aws cloudformation create-change-set --stack-name <stack> \
--change-set-name import-x --change-set-type IMPORT \
--capabilities CAPABILITY_NAMED_IAM \
--template-url https://<bucket>.s3.<region>.amazonaws.com/import-template.json \
--resources-to-import '[{"ResourceType":"AWS::SNS::Topic","LogicalResourceId":"...","ResourceIdentifier":{"TopicArn":"..."}}]'
aws cloudformation execute-change-set --stack-name <stack> --change-set-name import-x
This succeeded immediately on the same stack where cdk import failed, with the change set containing only the two intended Import actions — confirming the deployed state was never actually divergent. Imported resources need an explicit DeletionPolicy in that template.
Additional Information/Context
The underlying GetTemplate behaviour is a CloudFormation API limitation, reported and still open:
Related CDK history:
Since CloudFormation is unlikely to fix GetTemplate soon, mirroring aws/aws-cdk#25912's approach in the import path seems the practical fix. Filing this because the diff side was mitigated in 2023 while import still fails, and the error message gives no indication that character encoding is involved — it names an unrelated resource, which makes it very hard to diagnose.
AWS CDK Library version (aws-cdk-lib)
2.267.0
AWS CDK CLI version
2.1139.0 (build d51353e)
Node.js Version
v24.5.0
OS
macOS 26.5.2 (arm64)
Language
TypeScript
Describe the bug
cdk importfails on any stack whose deployed template contains a non-ASCII character in a resource property, even when the local code is byte-identical to what is actually deployed.Root cause:
cdk importbuilds its import template from the deployed template (CloudFormationGetTemplate) plus the resources being imported.GetTemplateis lossy — it replaces non-ASCII characters with a literal ASCII?. CDK therefore submits a template in which an untouched resource's property differs from what CloudFormation actually holds, and CloudFormation rejects the IMPORT change set:The named resource has not been modified by the user at all — the only difference is
—(U+2014) vs?.This is the same CloudFormation mangling already known to
cdk diff, which has masked it since aws/aws-cdk#25912 ("Omitted N changes because they are likely mangled non-ASCII characters. Use --strict to print them."). That masking was never applied to thecdk importcode path, so the problem is invisible incdk diffand then blockscdk importwith an error that points at an innocent resource.The affected property in our case is
AWS::IAM::ManagedPolicy.Description, which is create-only — so it cannot be "fixed" in place to work around the issue. Changing it forces a replacement, and sinceManagedPolicyNameis also create-only and fixed, replacement fails withEntityAlreadyExists. Affected users have no remediation path within CDK.Expected Behavior
cdk importsucceeds. A property whose deployed value differs from the local value only byGetTemplate's non-ASCII mangling should be treated as unchanged — the same waycdk diffhas treated it since aws/aws-cdk#25912.Current Behavior
cdk importfails during change-set creation:Verification that the resource is genuinely unmodified:
"Description": "Scoped IAM access for the app production role — App resources only."(U+2014)aws iam get-policy: returns the same string, with U+2014 intact — the live resource is correctaws cloudformation get-template: returns"Scoped IAM access for the app production role ? App resources only."(?, 0x3F)cdk diffreports no change to this resource, printing onlyOmitted 1 changes because they are likely mangled non-ASCII characters.Editing the local source to contain a literal
?does not help — the published import template is byte-identical either way, since the local source is not an input to it. That is what pinned the cause to theGetTemplateround-trip.Reproduction Steps
Synthesize a stack containing a resource with a non-ASCII character in a string property, e.g.:
cdk deploy.aws cloudformation get-template --stack-name <stack>— the description comes back with?instead of—.Add to the same stack a resource that already exists in the account and is intended for import (any importable type; we used an
AWS::SNS::Topicplus itsAWS::SNS::Subscription).cdk import <stack>and supply the physical identifier when prompted.Change-set creation fails with the
ValidationErrorabove, naming the policy — a resource not involved in the import.Possible Solution
Apply the mangling-aware comparison introduced in aws/aws-cdk#25912 to the import path: when building the import template, treat a deployed value that is the mangled form of the local value as unchanged. Alternatively, construct the import template from the synthesized template (which retains the true characters) rather than from
GetTemplateoutput.Workaround for anyone hitting this: bypass
cdk importand submit the change set directly, using the synthesized template as the base, so the true characters reach CloudFormation.This succeeded immediately on the same stack where
cdk importfailed, with the change set containing only the two intendedImportactions — confirming the deployed state was never actually divergent. Imported resources need an explicitDeletionPolicyin that template.Additional Information/Context
The underlying
GetTemplatebehaviour is a CloudFormation API limitation, reported and still open:Related CDK history:
cdk diffalways reports diff if resource has non-ASCII characterscdk diff(merged Jun 2023; added the--strictflag and the "Omitted N changes" message)cdk diff(follow-on)Since CloudFormation is unlikely to fix
GetTemplatesoon, mirroring aws/aws-cdk#25912's approach in the import path seems the practical fix. Filing this because thediffside was mitigated in 2023 whileimportstill fails, and the error message gives no indication that character encoding is involved — it names an unrelated resource, which makes it very hard to diagnose.AWS CDK Library version (aws-cdk-lib)
2.267.0
AWS CDK CLI version
2.1139.0 (build d51353e)
Node.js Version
v24.5.0
OS
macOS 26.5.2 (arm64)
Language
TypeScript