CloudFormation "Already Exists" Error: Import, Don't Delete

Logeshwaran
—

Don't delete it. When CloudFormation stops with an "already exists" error, the supported way forward is to import the existing resource into your stack: add the flag --import-existing-resources to a change set (called auto-import), or run an IMPORT change set with your template and the resource's identifier (manual import). Here's the part most guides skip: CloudFormation does not check that your template matches the real resource, so an import can finish cleanly and still leave you with a stack that wants to rewrite your live resource on the next update. Import first, then run drift detection.

⚡ Quick Answer

• Step 1 → Find out who owns the resource: nobody, another stack, or another account. Confirm its type supports import.

• Step 2, named resource → Give it a fixed name and a DeletionPolicy of Retain or RetainExceptOnCreate, then create the change set with --import-existing-resources. See auto-import.

• Step 2, anything else → Describe the resource exactly as it exists, add a DeletionPolicy, and run an IMPORT change set. See manual import.

• Step 3 → Run drift detection right away, because the import never compared your template to the real thing. See the drift section.

If you only read this box: adopt the resource, don't destroy it. Deleting is a last resort, and there's a short list of cases where it's fair.

Jake lost most of a Saturday to this error. He runs a small phone repair shop, and his booking page lets customers upload photos of a cracked screen or a water-damaged phone before they walk in. His nephew had set up the storage for those photos by hand, in the AWS console, a year earlier. Jake finally moved his setup into CloudFormation, AWS's service that builds cloud resources from a written description called a template, and the very first deploy died with a red line ending in "already exists."

The obvious fix was staring at him: delete the old storage and let CloudFormation make a fresh one. Ethan, who has cleaned up more of these than he'd like to admit, stopped him before he clicked anything. "Those photos are every customer's proof that their phone arrived with a cracked screen," Ethan said. "If they're in there, delete isn't on the menu yet." What follows is the route Ethan walked him through, plus every branch that comes up when the tidy version doesn't fit.

What the "already exists" error is really telling you

A stack is one deployed copy of a template: CloudFormation reads your written description, then builds and tracks the resources in it. Each resource in the template has a logical ID, the nickname you gave it inside the template. Once it exists in your account it also has a physical ID, the real name or identifier AWS assigned or accepted. The "already exists" error means CloudFormation tried to create a resource with a certain physical ID and found something already sitting there.

You'll usually see it on the stack's Events tab, in the Status reason column, in shapes like these:

Resource handler returned message: "my-bucket-name already exists"
(RequestToken: ..., HandlerErrorCode: AlreadyExists)

Resource of type 'AWS::IAM::Role' with identifier 'my-role-name' already exists.

Look at HandlerErrorCode: AlreadyExists. For people who build CloudFormation resource types, that code means the specified resource already existed before the handler ran, and it applies to create handlers only. That's a useful clue: CloudFormation was trying to create, not update. It walked up to a door it believed was an empty room and found somebody's furniture inside.

The wording changes from service to service, and the meaning doesn't. Here are the usual reasons the furniture is there:

  • A previous stack kept it. A resource with a DeletionPolicy of Retain stays behind when its stack is deleted. The stack shows DELETE_COMPLETE, but the resource lives on and keeps incurring any charges until you remove it. AWS CDK, a toolkit that generates CloudFormation templates from ordinary programming languages, sets a retain-style removal policy on stateful resources. If you gave those resources custom names, redeploying the same code trips over the leftovers.
  • Somebody built it by hand. Console-created resources are invisible to CloudFormation until you import them. This was Jake's situation.
  • The name is already taken in your account. IAM, AWS's permissions service, doesn't allow two roles with the same name in one account, so a template that hardcodes RoleName collides with a role from an earlier attempt or from another deployment of the same template.
  • Another stack owns it. Two stacks can't both manage one resource. This gets its own section below.
  • The name belongs to a stranger. Some names, S3 bucket names being the famous example, are shared across a whole AWS partition. If somebody else's account holds the name, importing can't help. That's covered in the hard cases.

Read the Events tab before you change anything

When a stack fails on its first creation, CloudFormation rolls it back, so the last lines of the Events tab are often rollback noise. Scroll up to the first failed event for the resource and read its Status reason. That's the line that names the physical ID you need in the next step. If several resources failed, take them one at a time. A single template can hit this error on a bucket, a role and a log group in the same deploy, and each one may need a different fix.

🧭 NEW HERE? READ THESE FIRST

Never imported a resource before? These basics make the steps below click:

⚡ Read these first if stacks and ARNs are still fuzzy.

Quick triage: who owns the thing that already exists?

Before you pick a fix, answer one question: whose is this resource right now? Everything else follows from the answer.

What you find What it means Go to
It's in your account and no stack manages it (hand-built, or left behind by a deleted stack) A good import candidate Auto-import if it has a fixed name, manual import if not
It's in your account and another stack manages it One resource can't be imported into two stacks in the same Region The "already in another stack" case
You can't find it anywhere in your account The name may belong to another account, or you're in the wrong Region The "someone else's name" case
It's yours but its type doesn't support import CloudFormation can't adopt it The "type doesn't support import" case
It's empty, brand new, and clearly left over from your own failed attempt Nothing to protect When deleting really is fine

To place your resource in that table, work through these steps in order:

  1. Copy the physical ID out of the error message. That's the bucket name, role name, table name, or ARN (the long unique address AWS gives every resource).
  2. Note the Region your stack deploys to. A Region is one of AWS's geographic locations, and most resources live in exactly one. Open that Region's console.
  3. Open the service's own console page (S3, IAM, DynamoDB, whichever it is) and look for the resource by its physical ID.
  4. Scan the Resources tab of your other CloudFormation stacks in that Region for the same physical ID. If one lists it, that stack owns it.
  5. Open the Resource type support page in the CloudFormation User Guide and look up your type's Import column, so you know before you start whether import is possible.
  6. If the resource holds data (a bucket with files, a table with rows, a database), make sure you have a copy somewhere else before you touch anything. That's ordinary caution, not a CloudFormation requirement.

Six steps sounds like a lot, but most take under a minute. Step 4 is the one people skip and regret. It's a bit like a printer that only jams on Mondays: the machine isn't broken, you're just looking at it on the wrong day. A resource that "doesn't exist" often just isn't where you're looking, whether that's the wrong Region, the wrong account, or a stack you'd forgotten about.

Why deleting is usually the wrong first move

The advice you'll find in plenty of forum threads goes: "Just delete the old one and redeploy." For a throwaway resource that's fine. For anything that holds data, it can turn into a real problem.

Start with what deletion involves. A resource with no DeletionPolicy is deleted by default when its stack goes. An S3 bucket, Amazon's file storage where each container of files is called a bucket, also has to be emptied of every object before it can be deleted. So "delete and recreate" for a bucket really means "delete every file, delete the bucket, then rebuild."

⚠️ What this actually breaks

Deleting an S3 bucket can cost you more than the files. After you delete a general purpose bucket, another AWS account in the same partition can use the same bucket name and can then receive requests that were meant for your old bucket. If you want to keep using the name, don't delete the bucket. If you delete a bucket to make room for CloudFormation, you may not get the name back.

🙋‍♂️ Jake's Reality Check

"My nephew has the photos on his laptop. Can't I just delete the bucket and upload them again?"

The straight answer. You could, but you'd take on a long upload, a stretch where the booking page has nowhere to put photos, and the chance that the bucket name gets claimed by someone else in the meantime. Import keeps the files where they are.

Here's how the popular fixes compare once you look at what each one actually does:

Popular advice What it does Verdict
Delete the existing resource and redeploy Removes the resource and its contents (a bucket must be emptied first); a bucket name may be claimed by another account afterward Only for empty, disposable leftovers
Rename the resource in your template Clears the error by creating a second, empty resource; the data stays in the old one, unmanaged Fine for stateless things, risky for stateful ones
Delete the failed stack and redeploy Needed when a stack sits in ROLLBACK_COMPLETE, but it doesn't remove the collision, so the same error returns Necessary sometimes, never sufficient alone
Import the existing resource Adopts the resource as it is into the stack, no delete and recreate The right default for anything with data

The rename trick deserves a special warning, because it looks like success. The error disappears, the deploy goes green, and your application now points at a new resource with nothing in it. The data you cared about is sitting in the old one, outside CloudFormation's care. Ethan calls it "the worst of the four, because it feels like a win."

AWS describes import as the tool for exactly this job: it lets you start using CloudFormation on resources created outside it, without deleting and recreating them.

DeletionPolicy, explained once so the rest makes sense

Every import route in this post asks for a DeletionPolicy, so it's worth understanding. It's a line you add to a resource in your template that tells CloudFormation what to do with the real thing when the stack, or the resource's entry in it, goes away. Here are the four options:

Value What CloudFormation does For imports
Delete Deletes the resource and its content on stack deletion. This is the default when no policy is set. A bucket must be emptied first. Accepted by manual import (any value satisfies the requirement), not by auto-import
Retain Keeps the resource and its contents. The stack reaches DELETE_COMPLETE, but the resource continues to exist and incur charges until you delete it. Accepted by both routes
RetainExceptOnCreate Acts like Retain except for the operation that first created the resource. If that creation rolls back, the resource is deleted. Otherwise it's kept. Accepted by both routes
Snapshot For types that support snapshots, takes a snapshot before deleting. Snapshots keep existing and incurring charges until you delete them. Accepted by manual import for a type that supports it

Some details from the same page matter for cleanups like this one. The policy also applies when a stack update removes a resource, for example when you delete its block from the template and update the stack. With Retain, the physical resource is kept but removed from CloudFormation's scope. Types with snapshot support include EC2 volumes, RDS instances and clusters, and Redshift clusters, among others. And for RDS clusters, plus RDS instances that don't set a cluster identifier, the default policy is Snapshot instead of Delete.

⚠️ What this actually breaks

Retain does not protect a resource that gets replaced. The capability doesn't apply when an update edits properties in a way that makes CloudFormation replace the resource: the old resource is completely deleted, including from CloudFormation's scope. So a retention policy protects you from removal, not from a template edit that triggers replacement. That's one more reason to import first, change later.

Route 1: auto-import with one flag

Auto-import is the newer, easier route. You describe the resource in your template with its real name. When you ask for it, CloudFormation checks for existing resources that match and imports them during the deployment instead of trying to create them.

🕐 What changed between versions

  • Before: to import, you had to hand CloudFormation a separate document naming each resource, and AWS's announcement notes you couldn't create or modify resources and import resources in the same change set.
  • Now: since AWS's announcement on November 17, 2023, the ImportExistingResources parameter on the CreateChangeSet API auto-imports resources that already exist, using the custom names in your template, inside deployments that create or update stacks.
  • What that means for the steps below: for named resources you can skip the separate identifier document. Resources that don't accept custom names in a template, such as EC2 instances, remain the job of manual import.

The five requirements

A resource has to meet all five of these to be auto-imported:

  • It has a static custom name in your template. A dynamic name built with !Ref or another function isn't currently supported.
  • Its DeletionPolicy is Retain or RetainExceptOnCreate.
  • It doesn't already belong to another CloudFormation stack.
  • Its resource type supports import operations.
  • The primary ID or an additional identifier for that type is in the template, and identifiers made of read-only properties aren't supported.

The template and the command

Here's a template for Jake's bucket. YAML is a plain-text way of writing structured settings where indentation shows what belongs to what. It's one of the two formats CloudFormation accepts, along with JSON.

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  PhotoBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      BucketName: jakes-repair-photos

Then you create a change set, which is CloudFormation's preview of what it's about to do. It lists the planned actions and lets you read them before anything runs. Here is the command, using the AWS CLI, the command-line tool for talking to AWS from a terminal:

aws cloudformation create-change-set \
  --stack-name my-stack \
  --change-set-name CreateChangeSet \
  --change-set-type CREATE \
  --template-body file://template.yaml \
  --import-existing-resources

Read the change set before you execute it, using the same commands the manual-import walkthrough uses: aws cloudformation describe-change-set with the change set name and stack name, then aws cloudformation execute-change-set with the same two values. For nested stacks, create the change set from the root stack, the top-level stack that contains the others.

Which resource types can auto-import?

Plenty of the common ones. The auto-import list includes AWS::S3::Bucket, AWS::DynamoDB::Table, AWS::IAM::Role, AWS::Lambda::Function, AWS::Logs::LogGroup, AWS::KMS::Alias, AWS::ECR::Repository, AWS::SSM::Parameter, AWS::Kinesis::Stream, AWS::StepFunctions::StateMachine, AWS::RDS::DBInstance and AWS::ECS::Cluster, along with hundreds more. When this was written the list did not include EC2 instances, SNS topics, SQS queues or VPCs. If you're working with one of those, read the current list on the page titled "Import AWS resources into a CloudFormation stack automatically" before planning around it.

✅ Why this is the one to use

If your resource has a fixed name, is a supported type, and you can add Retain, auto-import is the shortest path: no identifier file, no separate create-versus-import step, and it fits an automated pipeline. Ethan's opinion, stated flatly: "If it qualifies for auto-import, use auto-import. Manual import is the reliable fallback, not the first choice."

When auto-import fails

The checklist for a failed auto-import is short, and worth taking literally:

  • The resource name in your template must match the real name exactly.
  • The resource must not already be managed by another stack.
  • The resource type must support auto-import.
  • Your template must include all the required properties for the type.

A typo in a bucket name, or a hyphen where the real name has an underscore, is the classic culprit. CloudFormation looks for a match, finds none, and goes back to trying to create the resource, which lands you right back at "already exists." Copy the name from the service's console page instead of typing it from memory.

Route 2: manual import, step by step

Manual import is the older, more explicit route. It's slower, and it's what you use when auto-import doesn't apply: the resource has no custom name, the type isn't on the auto-import list, or you want tight control over exactly what gets adopted. You create a change set of type IMPORT that names each resource you're adopting and how to identify it.

What you need before you start

  • A template describing the whole stack. That means the resources already in the stack plus the ones you're importing. Save it locally or in an S3 bucket. To grab a running stack's template, open the stack in the console, go to the Template tab, and choose Copy to clipboard.
  • For each resource you import: the properties and values that define its current configuration, its unique identifier (such as its name), and a DeletionPolicy attribute. Any valid value satisfies the requirement, and resources already in the stack don't need one.
  • Two values to identify each resource: an identifier property and an identifier value. For an AWS::S3::Bucket, the property is BucketName and the value is the real bucket name. For an AWS::DynamoDB::Table, it's TableName. Which property identifies a resource varies by type. The console shows the options during the import wizard, and aws cloudformation get-template-summary with your template's S3 URL reports them from the CLI.

Here's the ground rule that surprises people: an import operation doesn't allow new resource creations, resource deletions, or changes to property configurations. It adopts, and only adopts. If you want to add a new resource and adopt an old one, that's two separate operations.

Status you'll see What it means
IMPORT_IN_PROGRESS The import is running
IMPORT_COMPLETE The import finished for every resource in the stack
IMPORT_ROLLBACK_IN_PROGRESS CloudFormation is rolling back to the previous template configuration
IMPORT_ROLLBACK_FAILED The rollback itself failed
IMPORT_ROLLBACK_COMPLETE The import rolled back to the previous template configuration

In the console

These steps follow the User Guide's console walkthrough for importing into an existing stack.

  1. Sign in to the AWS Management Console and open the CloudFormation console.
  2. On the Stacks page, choose the stack you want to import into.
  3. Choose Stack actions, then choose Import resources into stack.
  4. Read the Import overview page, then choose Next.
  5. On Specify template, choose Amazon S3 URL and paste your template's URL, or choose Upload a template file and browse for it. Then choose Next.
  6. On Identify resources, pick the Identifier property (for a bucket, BucketName) and type the Identifier value (the real bucket name) for each resource being imported. Choose Next.
  7. On Specify stack details, update any parameters, then choose Next. This automatically creates a change set. Don't change existing parameters in a way that triggers a create, update or delete, because the import fails if you do.
  8. On the review page, read the list of resources to import and choose Import resources. This runs the change set, and the Events tab shows progress.
  9. When it finishes, run drift detection on the stack, as the drift section below explains.

Two console notes. First, the console doesn't support the Fn::Transform function when importing, so a template that uses it needs the CLI route. Second, any stack-level tags you configured are applied to the imported resources at import time, so expect new tags to show up on the resource afterward.

With the CLI

  1. Find your identifier properties by running aws cloudformation get-template-summary --template-url followed by your template's S3 URL.
  2. Write the resources-to-import list as JSON. For Jake's bucket it looks like this:
[
  {
    "ResourceType": "AWS::S3::Bucket",
    "LogicalResourceId": "PhotoBucket",
    "ResourceIdentifier": { "BucketName": "jakes-repair-photos" }
  }
]
  1. Create the change set with --change-set-type IMPORT and --resources-to-import file://ResourcesToImport.txt, along with your stack name, change set name and template. Note that --resources-to-import doesn't accept inline YAML and that quote-escaping rules differ between terminals, which is why pointing at a file is the calmer choice.
  2. Review the change set with describe-change-set to see which resource is being imported.
  3. Run execute-change-set. When the stack reaches IMPORT_COMPLETE, the resources are imported.
  4. Run drift detection: detect-stack-drift, then describe-stack-drift-detection-status, then describe-stack-resource-drifts.

If the stack doesn't exist yet, the same feature can create a new stack from existing resources. The change set is still of type IMPORT, and it produces a fresh stack that starts out owning the resources you listed.

Ethan's advice on the template step, where most manual imports go wrong: "Describe the resource the way it is, not the way you wish it were. Import is not the moment to improve anything. Import first, change later." Jake's shop has the same rule for phone repairs on a busy afternoon. When a customer says they need it fixed by lunch, you fix what's broken and save the upgrades for later.

Route 3: let the IaC generator write the template for you

Writing a template that describes an existing resource property by property is tedious, and a typo can create a mismatch. IaC generator is CloudFormation's answer. (IaC stands for infrastructure as code, meaning your cloud setup described in files instead of clicked together by hand.) It scans your account for resources that aren't already managed by CloudFormation and writes a template from what it finds.

The process has three parts:

  • Scan. You start a scan of your resources. It's Region-wide and expires after 30 days, and during that time you can create multiple templates from the same scan.
  • Create a template. Either create one from scratch and add the scanned resources and related ones, or use an existing CloudFormation stack's template as the starting point.
  • Import. Use the template to import the resources as a CloudFormation stack, or to migrate them into an AWS CDK app.

The limits are worth knowing before you plan around it. The limits: a maximum of 500 resources in one template, five templates generating at once per account, and ten scans a day for scans with fewer than 10,000 resources. It also says the IaC generator only supports resources that Cloud Control API, an AWS service it relies on, supports in your Region. The scan covers only resources you have read access to. Missing permissions don't make the scan fail. They quietly leave those resources out, so if something you expect is missing, check your read permissions first.

CLI command What it's for
start-resource-scan Starts a scan of the resources in an account and Region
describe-resource-scan Monitors the progress of a scan
list-resource-scan-resources Lists what the scan found
list-resource-scan-related-resources Lists resources related to the scanned ones
create-generated-template Generates a template from a set of scanned resources
update-generated-template, describe-generated-template, list-generated-templates, delete-generated-template Updates, inspects, lists, or deletes generated templates

AWS's documentation also has a page called "Resolve write-only properties" in the same section. If your generated template raises anything about them, read that page before importing, rather than guessing.

The IaC generator earns its keep when you're adopting a handful of hand-built resources at once, or when you have no idea what the current settings are. For one bucket with a known name, it's more machinery than the job needs.

Picking the right route, then one full run

Route What it needs Use it when
Auto-import Static custom name, Retain or RetainExceptOnCreate, supported type The resource is named and supported, and you want the shortest or most pipeline-friendly path
Manual import Full template, a DeletionPolicy per imported resource, identifier property and value The resource has no custom name (an EC2 instance, say) or auto-import doesn't cover its type
IaC generator, then import A scan, read access, a type Cloud Control API supports Many resources at once, or you don't know the current settings
Move between stacks (Retain, remove, import) A Retain policy on the source resource, then an import into the target stack Another CloudFormation stack already owns the resource

Here's the whole thing as one checklist, using Jake's bucket as the example. It's Ethan's plan for a named, supported, unowned bucket, and it works as a template for yours:

  1. Copy the physical ID from the Events tab and find the resource in the console, in the right Region.
  2. Confirm no other stack lists it, and that its type has a Yes in the Import column.
  3. Copy the resource's real settings into the template so the description matches what exists.
  4. Add DeletionPolicy: Retain to the resource.
  5. Create the change set, with the import-existing-resources flag for a named resource or the IMPORT type for a manual import.
  6. Read the change set. It should show the resource being imported, not created.
  7. Execute it and wait for IMPORT_COMPLETE (or the deployment's normal completed status for auto-import).
  8. Run drift detection and fix any mismatch before the next stack update.

After the import: drift detection and the mismatch trap

This is the part the opening paragraph warned about. During an import, CloudFormation checks that the resource exists, that your properties fit the resource type's schema, that required properties are present, and that the resource doesn't belong to another stack in the same Region. What it does not do is compare your template to the resource's actual configuration. One warning: make sure the resources and properties in your template match the intended configuration, to avoid unexpected changes.

Why does that matter? After a successful import, CloudFormation treats your template as the truth. If the template says one thing and the live resource says another, the difference sits there until your next stack update, and then CloudFormation may try to make the resource match the template. On a bucket that might be a setting. On a database it could be something you'd much rather not touch.

Drift is the word for this gap: the real resource has wandered away from what the template says. Drift detection is CloudFormation's built-in comparison, and I recommend running it after an import completes and before later stack operations. The console route is Stack actions, then Detect drift. From the CLI it's three commands:

aws cloudformation detect-stack-drift --stack-name TargetStack
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id <id-from-previous-step>
aws cloudformation describe-stack-resource-drifts --stack-name TargetStack

The first returns a detection ID, the second reports progress, and the third lists resources with their expected and actual settings.

If drift shows up

You have two honest choices. Either correct the template so it matches the resource (usual when the resource is right and your description was sloppy), or update the resource directly if the template is right. AWS also documents a third route for when you want to accept the resource's live settings as the new truth, and a plain stack update would force a replacement. It's called resolving drift with an import operation, and it has three steps:

  1. Add DeletionPolicy: Retain to the drifted resource and update the stack.
  2. Remove the resource, along with its related parameters and outputs, from the template and update the stack again. The resource's status on the Events page becomes DELETE_SKIPPED, meaning CloudFormation let go without deleting.
  3. Describe the resource's actual state in the template and import it back. The Events tab shows IMPORT_COMPLETE followed by CREATE_COMPLETE with the status reason "Resource import complete."

The classic example is a DynamoDB table, a managed database table, whose billing mode was changed outside CloudFormation to pay-per-request. Resolving it by import keeps the table in service throughout, and the template ends up describing the mode the table actually uses.

🙋‍♂️ Jake's Reality Check

"The import said it worked. Why run another check? It feels like proofreading my own receipt."

The straight answer. Because "it worked" only means CloudFormation adopted the resource. It never compared your description to the real thing. Drift detection does that comparison, and it costs a few minutes, compared with an unplanned change on your next stack update.

The hard cases: when the plain import doesn't fit

Most posts on this error stop after the happy path. Here's what to do when it doesn't apply, which is exactly when readers land on this page.

It already belongs to another stack

You can't import the same resource into multiple stacks in the same Region, and the import validation refuses a resource that another stack in the Region owns. A few resource types aren't Region-specific, and AWS names IAM roles, Route 53 hosted zones and CloudFront distributions as examples. For those, the check applies per Region, so you have to make sure yourself that a stack in another Region isn't already managing the resource.

If you want the resource in the new stack, you're moving it, and the steps are:

  1. In the source stack's template, add DeletionPolicy: Retain to the resource and update the stack.
  2. Remove the resource, plus related parameters and outputs, from the source template, and add it to the target template. Update the source stack again so it lets go of the resource.
  3. Run an import operation on the target stack, using the identifier property and value as before.

You don't need to run drift detection on the target stack after this move, because the resource is already managed by CloudFormation. CloudFormation also has a stack refactoring feature meant for moving resources between stacks, splitting large stacks, or merging several while preserving properties and data. Read its page before you start, because it may replace the manual sequence.

⚠️ What this actually breaks

AWS's warning here is blunt: if you remove a resource that doesn't support import operations from your stack, you can't import it into another stack or bring it back into the source stack. Before step 2, look the resource type up on the Resource type support page and confirm import is supported.

The name belongs to someone else's account

This one has no import fix, and it's worth saying plainly. By default, S3 general purpose buckets live in a global namespace: each bucket name must be unique across all AWS accounts in all Regions of a partition. Once a bucket exists, the name is unavailable to anyone else. If a stranger's account holds the name your template asks for, CloudFormation reports that it already exists, you won't find it in your own console, and no import will help. There is no supported way to import a resource that lives in another account, so plan on that not being possible.

Your options are to choose a different name, or to leave BucketName out of the template so CloudFormation generates one. AWS has also added an account regional namespace for general purpose buckets: only your account can create buckets in it, and the bucket name has to include the AWS Region in its suffix. If you're planning new buckets, look into S3 namespaces, which are designed to take this collision off the table.

The resource type doesn't support import

Not everything can be imported. The Resource type support page lists which types can, in an Import column, and the IaC generator only covers types that Cloud Control API supports. If your type isn't importable, you have two real paths:

  • Stateless resource: creating a replacement is often acceptable. For things like IAM roles, Lambda functions and event rules, creating new resources is sometimes fine. Rename the resource, let CloudFormation create the new one, and retire the old one on your schedule.
  • Stateful resource: this is the hard one. Creating new versions of stateful resources such as S3 buckets and DynamoDB tables can affect your service. If a stateful type truly can't be imported, plan a data migration with a proper window instead of a swap.

Your failed stack is stuck in ROLLBACK_COMPLETE

When a stack fails on its very first creation, CloudFormation rolls it back and the stack lands in ROLLBACK_COMPLETE. A stack in that state can't be updated: delete it, then deploy again, and this time use one of the import routes above. They also mention that you can disable automatic rollback for future deployments to keep a failed creation from landing in that state, which is worth considering while you're debugging. Before you delete, read the stack's Resources tab so you know what, if anything, it owns.

You're using the AWS CDK

CDK users hit this error more than anyone, and here's why: CDK sets the removal policy of stateful resources to retain, so when you delete a stack the buckets and tables stay behind. If you gave them custom names, redeploying the same code produces "Already Exists." That article's recommended answer is the same auto-import feature described above.

The CDK also has its own command. cdk import takes existing resources and starts managing them in a new or existing CDK app: you add constructs for the resources to your stack, then run cdk import. Import one or a few resources at a time this way, and note that importing into nested stacks isn't possible. To convert a whole CloudFormation stack or template into a new CDK app, there's cdk migrate, which uses cdk import under the hood and can migrate a single CloudFormation stack into a single stack in the new app.

Nested stacks

A nested stack is a stack that lives inside another stack, like a folder inside a folder. For auto-import, create the change set from the root stack. For manual import, CloudFormation supports only one level of nesting: you can't import a stack into a child stack, and you can't import a stack that has children. To adopt an existing stack as a nested one, the method adds an AWS::CloudFormation::Stack resource to the parent template with a Retain deletion policy, then imports it through Stack actions. That import validates that the nested stack definition in the parent matches the actual nested stack's template, and drift detection on the parent isn't needed afterward.

Some types behave oddly after import

Import gets a resource into the stack, but that doesn't guarantee every later update goes smoothly. One reported case: a CloudTrail resource policy imported fine and drift detection worked, but later updates failed with an invalid request error, and the workaround was to manage that policy with the AWS CLI instead. It's one report, not a rule, but it's a good reason to make your first post-import stack update a small, low-risk one and to keep drift detection in your routine.

When deleting really is the right call, and when nothing works

Ethan isn't against deleting. He's against deleting first. There's a short list of cases where it's a reasonable call:

  • The resource is empty, brand new, and left over from your own failed attempt, with nothing depending on it. This is exactly the situation RetainExceptOnCreate is designed for: a rolled-back creation cleans up new, empty, unused resources, while resources in use are kept.
  • Its type doesn't support import, it's stateless, and replacing it is cheaper than a workaround.
  • You've confirmed nothing points at it, and you have its data or settings somewhere safe.

Even then, write down the resource's settings before you remove it, so recreating it is a copy job rather than a memory test.

When none of the routes work, the honest options are these. Choose a different name, or let CloudFormation generate one by leaving the name property out of your template. Rebuild the resource under a fresh name and migrate the data by hand. Or, if the error points at something you can't explain, such as a name you can't find in any account you control, open a case with AWS Support rather than guessing further. And the limit that can't be argued with: if you don't own the name and don't own the resource, nobody can import it for you.

For a resource like Jake's, the answer stays short. The bucket is named, it's a supported type, no stack owns it, and it holds files worth protecting. That's the textbook import case: add Retain, run the change set with the import flag, read the plan, execute, then run drift detection and fix the template wherever it disagrees with the bucket. The photos stay where they are throughout.

Keeping it from happening again

A few habits cut the frequency of this error sharply.

  • Let CloudFormation name things when the name doesn't matter. A related trap with IAM roles: if you deploy multiple copies of a template, you shouldn't set RoleName, since no two roles in an account can share a name. The same idea holds for any resource whose name only needs to be unique.
  • Choose your deletion policy on purpose. Retain protects data and leaves the resource behind, which is what causes name collisions on redeploy. RetainExceptOnCreate keeps in-use resources but cleans up new, empty ones when a first creation rolls back, which prevents a lot of leftover-name errors.
  • Import hand-built resources early. The longer a console-built resource lives outside CloudFormation, the more its real settings can drift from anything you'd write in a template.
  • Automate the import where it fits. AWS's announcement says the import parameter reduces manual steps and lets CI/CD (automated build-and-deploy pipelines) handle cases where you only want to import resources with custom names.
  • Run drift detection on a schedule of your own. A small gap found in a calm week is cheaper than a big one found in a hurry.

Ethan's summary for Jake: "Treat the template as the one place changes happen. The console is for looking, not for editing." Jake thought that was harsh, given that his nephew built the bucket in the console in the first place. "Everybody's first cloud setup starts in the console," Ethan said. "You just don't want it to be your only one."

Permissions, limits and the small print

A few loose ends that trip people up:

  • Stack limits still apply. An import doesn't get an exemption from CloudFormation's quotas, so a very large stack can hit a limit while adopting resources.
  • You can restrict who imports what. Administrators can use the cloudformation:ImportResourceTypes IAM policy condition to control which resource types people can work with during an import. If an import is denied for one type but not another, that condition is a good suspect.
  • Parameters are frozen during an import. Changing existing parameters in a way that triggers a create, update or delete makes the operation fail.
  • Templates can live locally or in S3. The CLI's --template-url takes an S3 URL, while --template-body file:// reads a local file.
  • You can revert an import. To back out, set a Retain deletion policy on the resource you want out of the stack, then update the stack with the resource removed. The resource stays, and it's simply no longer managed.
  • Only imported resources need a deletion policy for the import. Resources already in the stack don't.
  • Timing is a personal choice. Jake's router drops the connection on Sunday evenings, just when he'd otherwise be mid-deploy, so he schedules this kind of work for a quiet weekday morning and reads the change set slowly. It's not in any official guide, and it's still good habit.

Frequently asked questions

Can I import a resource that already exists into CloudFormation without deleting it?

Yes. Resource import exists for exactly this purpose: bringing resources created outside CloudFormation under its management without deleting and recreating them. You can auto-import named resources with the import-existing-resources option on a change set, run a manual IMPORT change set with your template and the resource's identifier, or generate a template with the IaC generator first. The resource has to be a supported type and can't already belong to another stack in the same Region.

What does HandlerErrorCode AlreadyExists mean in CloudFormation?

It means the resource CloudFormation tried to create was already present before the create handler ran. For people building resource types, this error code applies to create handlers only, so it tells you CloudFormation was creating rather than updating. The fix is to bring the existing resource into the stack by importing it, or to choose a different name if the existing one isn't yours.

What is the --import-existing-resources flag in CloudFormation?

It's the AWS CLI option that sets the ImportExistingResources parameter on a create-change-set call. When it's on, CloudFormation checks for existing resources that match your template's custom names and imports them during a deployment that creates or updates a stack. The resources need a static custom name, a DeletionPolicy of Retain or RetainExceptOnCreate, a supported type, and no owner among your other stacks.

Why does CloudFormation require a DeletionPolicy to import a resource?

The requirement is simple, even if the reason isn't spelled out: each resource you import must have a DeletionPolicy attribute for the operation to succeed, and any valid value works. Retain is the safe habit, since it keeps the real resource if it's later removed from the stack. Resources already in the stack don't need one. Auto-import is stricter and accepts only Retain or RetainExceptOnCreate.

Can I import the same resource into two stacks?

No. You can't import the same resource into multiple stacks in the same Region. A few types, such as IAM roles, Route 53 hosted zones and CloudFront distributions, aren't Region-specific, so for those you need to make sure a stack in another Region doesn't already manage the resource. To move a resource between stacks, retain it in the source stack, remove it, and import it into the target.

Does importing a resource change it?

The import operation doesn't allow property changes, new resources or deletions, so it adopts the resource as it is. One side effect: any stack-level tags are applied to the imported resources when the import runs, so expect tags to appear. Your bigger risk is a template that doesn't match the resource, which surfaces later. Run drift detection after the import and before later stack updates.

Does the import fail if my template doesn't match the real resource?

Not necessarily. CloudFormation validates that the resource exists, that your properties fit the type's schema, that required properties are present, and that no other stack in the Region owns it. It doesn't check that the template configuration matches the actual configuration. That's why I recommend drift detection right after an import, and why you should write the template to match the resource as it really is.

Which AWS resource types can I import into a stack?

A wide range, but not everything. The CloudFormation User Guide has a Resource type support page with an Import column for each type, and a separate list of types that support auto-import. Common ones include S3 buckets, DynamoDB tables, IAM roles and Lambda functions. Check before you remove a resource from any stack, because a resource whose type doesn't support import can't be imported elsewhere or brought back.

Can I import an S3 bucket that belongs to another AWS account?

Plan on no. There is no supported way to import a resource from a different account. By default, S3 bucket names are unique across all accounts in a partition, and once a bucket exists, nobody else can create that name. If another account holds the name your template wants, choose a different name, let CloudFormation generate one, or look into the account regional namespace for general purpose buckets.

How do I find the identifier CloudFormation needs for the import?

Each resource type has a property that identifies it, such as BucketName for an S3 bucket or TableName for a DynamoDB table. In the console, the Identify resources page lets you choose the property and type its value. On the CLI, run get-template-summary with your template's S3 URL to see the identifier properties, then take the value (the real name) from the service's own console page.

Can I create and import resources in the same change set?

For a manual import, no: an import operation doesn't allow new resource creations, deletions or property changes, so do them in separate operations. Auto-import is different. AWS's announcement describes the import-existing-resources parameter as working inside deployments that create or update stacks, so new and existing named resources can go through together.

What should I do if my failed stack is stuck in ROLLBACK_COMPLETE?

A stack in ROLLBACK_COMPLETE can't be updated and has to be deleted before you deploy again. Before deleting, look at what the stack owns on its Resources tab. Then redeploy using auto-import or a manual import, so the same collision doesn't send the new stack straight back into rollback.

How do I import an existing resource into an AWS CDK app?

Add a construct for the resource to your CDK stack, then run the cdk import command. Import one or a few resources at a time, and note that importing into nested stacks isn't possible. To convert a whole CloudFormation stack or template into a new CDK app, use cdk migrate instead. CDK's retained stateful resources with custom names are a common cause of this error on redeploy.

What happens to an imported resource when I delete the stack?

It follows its DeletionPolicy. With Retain, CloudFormation keeps the resource, and the stack reaches DELETE_COMPLETE while the resource continues to exist and incur any charges. With Delete, CloudFormation deletes the resource and its content, and an S3 bucket must be emptied first. RetainExceptOnCreate behaves like Retain for stack deletion. Decide on the policy deliberately before you delete any stack.

Can I move a resource from one stack to another instead of importing it fresh?

Yes, and the approach is import. Add a Retain policy to the resource in the source stack and update, remove it from the source template and update again, then import it into the target stack. Confirm the type supports import first, since an unsupported type can't be brought back. CloudFormation also offers stack refactoring for reorganizing resources between stacks while preserving their properties and data.

Should I just delete the resource and let CloudFormation recreate it?

Only if it's empty, new, unused and left over from your own failed attempt, or a stateless resource whose type can't be imported. For anything holding data, importing is safer. For S3, AWS also notes that once a bucket is deleted, another account can claim its name, so you may not get it back. If you do delete, write down the settings first.

πŸ“– ALSO READ

Imported cleanly? These are the neighboring errors people hit the same week:

⚡ Bookmark these — they solve the naming and permission errors that follow an import.

Revision note. Written September 2026, covering the AWS Management Console and the AWS CLI for CloudFormation manual import, auto-import, the IaC generator, and the AWS CDK import commands. It will need updating if AWS changes the auto-import requirements, adds resource types to the supported lists, or renames console pages. If you've been staring at that red "already exists" line for hours, you haven't done anything wrong, and there's a good chance your data is still safe right where you left it.

Related