The duplicate resource error occurs when Terraform detects two or more resources with the same resource address in your configuration. This typically happens when resource blocks are defined twice in the same module or when using meta-arguments like count or for_each incorrectly.
In Terraform, each resource must have a unique address within its scope (module). The address is composed of the resource type and resource name, like aws_instance.web or azurerm_resource_group.main. When Terraform parses your configuration, it builds an internal graph of all resources. If it finds two resources with the same type and name in the same module, it cannot determine which one you intend to manage, leading to the duplicate resource error. This error can occur in several scenarios: (1) you explicitly defined the same resource block twice in your .tf files, (2) you're using count or for_each incorrectly, causing indexes to collide, (3) modules are being instantiated with conflicting resource names, or (4) the same configuration file is being included multiple times through terraform modules or file globbing patterns.
Use your editor's search function to find all occurrences of the problematic resource. The error message will tell you which resource is duplicated.
# For example, if the error mentions aws_instance.web:
# In VS Code: Ctrl+F (or Cmd+F on Mac)
# Search for: resource "aws_instance" "web"
# Or use grep from the command line:
grep -r 'resource "aws_instance" "web"' .Look through all .tf files in your configuration and any modules you're using. Count how many times the resource appears—there should be only one definition.
Once you've found the duplicate definition, decide which one to keep and remove or rename the other.
Option 1: Delete the duplicate block
# Keep this one:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
# Delete this (the duplicate):
# resource "aws_instance" "web" {
# # ... configuration ...
# }Option 2: Rename one of them
resource "aws_instance" "web_primary" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
resource "aws_instance" "web_secondary" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}If you renamed a resource, you'll also need to update any references to it elsewhere in your configuration.
If the duplicate appeared while refactoring between count and for_each, ensure your meta-arguments don't create overlapping resource addresses.
Correct count usage:
resource "aws_instance" "web" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "web-${count.index}"
}
}
# Access: aws_instance.web[0], aws_instance.web[1], aws_instance.web[2]Correct for_each usage:
resource "aws_instance" "web" {
for_each = toset(["primary", "secondary", "tertiary"])
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "web-${each.value}"
}
}
# Access: aws_instance.web["primary"], aws_instance.web["secondary"], etc.Never use both count and for_each on the same resource, and ensure your iteration values don't overlap.
If you renamed a resource, update all references throughout your configuration to use the new name. This includes:
- Other resource dependencies (depends_on)
- Outputs
- Data source references
- Module inputs
Before (using aws_instance.web):
resource "aws_security_group" "web" {
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
}
}
resource "aws_network_interface_sg_attachment" "web" {
security_group_id = aws_security_group.web.id
network_interface_id = aws_instance.web.primary_network_interface_id
}After (if you renamed to aws_instance.web_primary):
resource "aws_network_interface_sg_attachment" "web" {
security_group_id = aws_security_group.web.id
network_interface_id = aws_instance.web_primary.primary_network_interface_id # Updated reference
}Use your editor's find-and-replace to update all references at once.
After making changes, validate the syntax and check for errors:
# Validate the configuration syntax
terraform validate
# Format your configuration for consistency
terraform fmt -recursive
# Generate a plan to see what Terraform intends to do
terraform planIf terraform validate passes without errors and terraform plan shows the expected changes, you've successfully resolved the duplicate resource error. Review the plan carefully to ensure it matches your intentions before applying.
When refactoring from count to for_each, Terraform treats the resource addresses as completely different, which requires migrating state. You cannot directly switch from resource.web[0] to resource.web["key"] without using terraform state mv to repoint the state entries. For example: terraform state mv 'aws_instance.web[0]' 'aws_instance.web["primary"]'. If you have multiple resource files being included through terraform modules, ensure each module has its own resource namespace. A best practice is to avoid duplicate resource types within a module and use module composition instead. When using generated modules or infrastructure-as-code frameworks that generate Terraform code, verify that the generation logic doesn't create duplicate resources. If you're version controlling Terraform code and merging branches, merge conflicts might silently leave duplicate resources—review merge diffs carefully.
Error: 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