The ResourceExistsException error occurs when you try to create an AWS Transfer Server that already exists in your account or region. This typically happens due to Terraform state mismatch, duplicate resource definitions, or resources created outside of Terraform. Resolve it by importing the existing resource or removing duplicates.
AWS Transfer Family returns a ResourceExistsException when the `CreateServer` API call detects that a Transfer Server with the same configuration already exists in your AWS account within that region. This is a safety mechanism to prevent duplicate resource creation. Unlike most AWS errors, ResourceExistsException can occur in several scenarios: 1. **Duplicate manual creation**: You created the server manually in AWS Console or via AWS CLI, and now Terraform is trying to create it again. 2. **State file mismatch**: Your Terraform state file is out of sync with actual AWS resources. Terraform thinks the server doesn't exist, but it does. 3. **Concurrent resource creation**: Multiple Terraform workspaces or manual operations created the same server simultaneously. 4. **Region-specific**: Transfer Servers are region-specific. If you're deploying to multiple regions, ensure you're not creating duplicates. When Terraform encounters this error during `terraform apply`, it cannot complete the resource creation and your deployment fails.
List all Transfer Servers in your AWS region to see if it already exists:
aws transfer list-servers --region us-east-1Look for a server with the same endpoint or hostname that matches your Terraform configuration. You can also check the AWS Console by going to AWS Transfer Family > Servers.
If the server exists, note its Server ID (format: s-1234567890abcdef0). This is what you'll need to import into Terraform.
Review what Terraform thinks currently exists in your state file:
terraform state list | grep aws_transfer_serverIf nothing appears, Terraform's state is empty for Transfer Servers. This indicates a state mismatch.
To refresh your state with actual AWS resources:
terraform refreshThis updates your local state to match what actually exists in AWS. If the server appears after refresh, re-run:
terraform planThe plan should show zero changes if everything is now in sync.
If the server exists in AWS but not in your Terraform state, import it:
terraform import aws_transfer_server.example s-1234567890abcdef0Replace s-1234567890abcdef0 with your actual server ID from step 1.
After import, Terraform will fetch all the server's attributes from AWS and add them to your state file. Your resource block should match the imported configuration:
resource "aws_transfer_server" "example" {
identity_provider_type = "API_GATEWAY"
# ... other attributes will be populated
}Verify the import succeeded:
terraform state show aws_transfer_server.exampleTo prevent state mismatch issues, use a remote backend instead of local state. AWS S3 + DynamoDB is recommended:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "transfer-server/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}Initialize the backend:
terraform initAlternatively, use Terraform Cloud:
terraform {
cloud {
organization = "my-org"
workspaces {
name = "transfer-servers"
}
}
}A remote backend ensures your state is shared across team members and CI/CD systems, preventing duplicate resource creation.
If you have duplicate resource definitions in your Terraform code, remove the duplicate:
Instead of:
resource "aws_transfer_server" "main" {
identity_provider_type = "API_GATEWAY"
domain = "SFTP"
}
resource "aws_transfer_server" "main" {
# Accidentally duplicated
identity_provider_type = "API_GATEWAY"
domain = "SFTP"
}Keep only one resource block. Then run:
terraform planThe plan should show no changes. If it tries to destroy and recreate, don't apply—instead, import the existing resource as shown in step 3.
Once you've imported the resource or fixed the state mismatch, validate your configuration:
terraform validate
terraform planThe plan should show no changes if everything is correctly synced. If it still wants to apply changes, review them carefully—they may represent intentional infrastructure updates.
terraform applyIf applying succeeds with zero changes, your issue is resolved. The Transfer Server is now properly tracked in Terraform state.
Why remote state matters: Terraform state is a critical file. Without remote state, each team member has their own local state file. When different people apply Terraform from different machines, they can create duplicate AWS resources because their state files are out of sync. Always use remote backends (S3, Terraform Cloud, etc.) in production.
Region considerations: Transfer Servers are regional resources. A server in us-east-1 won't conflict with a server in eu-west-1, even with identical configuration. However, within a single region, server configuration must be unique.
Identity provider mismatch: If you're toggling between API_GATEWAY and SERVICE_MANAGED identity providers, AWS may see this as a different server. Ensure your Terraform code consistently defines the same identity provider type.
Endpoint/domain uniqueness: Each Transfer Server in your account must have a unique endpoint. If you're creating multiple servers, they must have different domain names or port configurations to avoid conflicts.
Team collaboration: If multiple team members use the same AWS account, use distinct resource names or separate workspaces. Use Terraform workspaces to manage multiple infrastructure environments:
terraform workspace new staging
terraform workspace select staging
terraform applyError: Error rendering template: template not found
How to fix "template not found" error in Terraform
Error: Error generating private key
How to fix 'Error generating private key' in Terraform
Error creating Kubernetes Service: field is immutable
How to fix "field is immutable" errors in Terraform
Error: Error creating local file: open: permission denied
How to fix "Error creating local file: permission denied" in Terraform
Error: line endings have changed from CRLF to LF
Line endings have changed from CRLF to LF in Terraform