cli: cdk import fails on stacks containing non-ASCII characters (GetTemplate mangling)
- Dominant language
- TypeScript
- Stars
- 105
- Forks
- 122
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 71
Description
### 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 [] 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
1. Synthesize a stack containing a resource with a non-ASCII character in a string property, e.g.:
```ts
new iam.ManagedPolicy(this, 'Policy', {
managedPolicyName: 'my-policy',
description: 'Scoped access — resources only.', // U+2014 EM DASH
statements: [ /* ... */ ],
});
```
2. `cdk deploy`.
3. `aws cloudformation get-template --stack-name ` — the description comes back with `?` instead of `—`.
4. 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`).
5. `cdk import ` and supply the physical identifier when prompted.
6. 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.
```bash
aws s3 cp import-template.json s3:///import-template.json
aws cloudformation create-change-set --stack-name \
--change-set-name import-x --change-set-type IMPORT \
--capabilities CAPABILITY_NAMED_IAM \
--template-url https://.s3..amazonaws.com/import-template.json \
--resources-to-import '[{"ResourceType":"AWS::SNS::Topic","LogicalResourceId":"...","ResourceIdentifier":{"TopicArn":"..."}}]'
aws cloudformation execute-change-set --stack-name --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:
- aws-cloudformation/cloudformation-coverage-roadmap#814 (Mar 2021) — GetTemplate/DescribeStacks do not properly return UTF-8 characters
- aws-cloudformation/cloudformation-coverage-roadmap#1220 (Jun 2022) — GetTemplate API does not support non-ASCII characters
Related CDK history:
- aws/aws-cdk#10523 — `cdk diff` always reports diff if resource has non-ASCII characters
- aws/aws-cdk#25912 — Hide diffs of mangled Unicode strings in `cdk diff` (merged Jun 2023; added the `--strict` flag and the "Omitted N changes" message)
- aws/aws-cdk#26703 — Unicode characters not properly recognised by `cdk diff` (follow-on)
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
Contributor guide
Research direction
Start by reproducing the failure with cdk import and compare the deployed template from CloudFormation GetTemplate with the synthesized template and the behavior already used by cdk diff. Trace the cdk import template-building path and its change-set creation. Done means an unchanged resource containing a mangled non-ASCII value no longer blocks the import, while the intended resources still produce Import actions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- cli, cloud, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100