Fix: Terraform Import Error — Resource Not Importable or State Conflict
Quick Answer
How to fix Terraform import errors — terraform import syntax, import blocks (Terraform 1.5+), state conflicts, provider-specific import IDs, and importing existing infrastructure.
The Problem
terraform import fails with an error:
terraform import aws_s3_bucket.my_bucket my-existing-bucket
# Error: Resource already managed by Terraform
# Error: Cannot import non-existent remote object
# Error: error reading S3 Bucket (my-existing-bucket): NoSuchBucketOr the import succeeds but terraform plan still shows changes:
terraform plan
# aws_s3_bucket.my_bucket will be updated in-place
# ~ versioning {
# ~ enabled = false -> true
# }
# Plan: 0 to add, 1 to change, 0 to destroy.Or import blocks in Terraform 1.5+ don’t generate a resource config as expected:
terraform plan -generate-config-out=generated.tf
# Error: Unsupported argumentWhy This Happens
terraform import brings existing infrastructure under Terraform management, but it only writes to the state file — it does NOT generate the Terraform configuration. Several things go wrong:
- Missing resource configuration — you must write the resource block in your
.tffiles before importing. Without it, Terraform doesn’t know what to manage. - Wrong import ID format — every resource type has its own import ID format.
aws_s3_bucketuses just the bucket name, butaws_db_instanceuses the DB instance identifier, and some resources use ARNs. Using the wrong format causesCannot import non-existent remote object. - State conflict — the resource is already in the state file (from a previous import or
terraform apply). Re-importing over an existing state entry requires removing it first. - Config drift after import — the import writes current state, but if your
.tfconfig doesn’t match the actual resource configuration, Terraform will show a plan to change the resource.
Fix 1: Correct terraform import Syntax
The basic import command requires an existing resource block in your config:
# Syntax: terraform import <resource_type>.<resource_name> <import_id>
terraform import aws_s3_bucket.my_bucket my-existing-bucket-name
# With a module
terraform import module.storage.aws_s3_bucket.my_bucket my-existing-bucket-name
# With a resource that has a count index
terraform import 'aws_s3_bucket.buckets[0]' bucket-name-0
# Note: quote the address to prevent shell interpretation of brackets
# With a resource that uses for_each
terraform import 'aws_s3_bucket.buckets["production"]' production-bucket-nameWrite the resource block BEFORE importing:
# main.tf — add this before running terraform import
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-existing-bucket-name"
# Add other required/known attributes
# You don't need all attributes — Terraform fills in the rest from state
# But attributes in the config must match the real resource
}Fix 2: Find the Correct Import ID
Every resource type has a specific import ID format. Check the provider docs:
# AWS resources — common import ID formats
# S3 bucket — just the bucket name
terraform import aws_s3_bucket.example my-bucket-name
# EC2 instance — instance ID
terraform import aws_instance.example i-1234567890abcdef0
# RDS instance — DB identifier (not ARN)
terraform import aws_db_instance.example my-db-instance
# IAM role — role name
terraform import aws_iam_role.example my-role-name
# IAM policy — policy ARN
terraform import aws_iam_policy.example arn:aws:iam::123456789:policy/MyPolicy
# Security group — group ID
terraform import aws_security_group.example sg-0123456789abcdef0
# VPC — vpc ID
terraform import aws_vpc.example vpc-0123456789abcdef0
# Route53 record — format: zone_id_RECORD_NAME_RECORD_TYPE
terraform import aws_route53_record.example Z1234567890ABC_example.com_ALook up the import ID format in the provider registry:
# Open the provider docs for the resource
# URL pattern: registry.terraform.io/providers/hashicorp/<provider>/latest/docs/resources/<resource>
# Or use the Terraform CLI
terraform providers schema -json | jq '.provider_schemas."registry.terraform.io/hashicorp/aws".resource_schemas."aws_s3_bucket"'Google Cloud and Azure examples:
# GCP — Cloud SQL instance
terraform import google_sql_database_instance.example projects/my-project/instances/my-instance
# Azure — Resource Group
terraform import azurerm_resource_group.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg
# Azure — Virtual Machine
terraform import azurerm_virtual_machine.example /subscriptions/.../resourceGroups/mygroup/providers/Microsoft.Compute/virtualMachines/myvmFix 3: Use Import Blocks (Terraform 1.5+)
Terraform 1.5 introduced import blocks as a declarative alternative to the CLI command. They’re reproducible, reviewable, and can generate config:
# import.tf — define what to import
import {
id = "my-existing-bucket-name"
to = aws_s3_bucket.my_bucket
}
# The resource block must still exist (or be generated)
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-existing-bucket-name"
}# Run terraform plan to see what will be imported
terraform plan
# Apply to execute the import
terraform apply
# After apply, the import block can be removed (it's a one-time operation)Generate resource config automatically (Terraform 1.5+):
# Step 1: Write just the import block (no resource block yet)
# import.tf
cat > import.tf << 'EOF'
import {
id = "my-existing-bucket-name"
to = aws_s3_bucket.my_bucket
}
EOF
# Step 2: Generate the resource configuration
terraform plan -generate-config-out=generated_resources.tf
# Step 3: Review the generated config, then apply
cat generated_resources.tf
terraform applyNote:
-generate-config-outrequires Terraform 1.5+. The generated config is a starting point — review it for accuracy before committing.
Fix 4: Fix State Conflicts
If the resource is already in state, re-importing requires removing it first:
# List resources in state
terraform state list
# Check current state of a resource
terraform state show aws_s3_bucket.my_bucket
# Remove from state (does NOT destroy the actual resource)
terraform state rm aws_s3_bucket.my_bucket
# Now you can re-import
terraform import aws_s3_bucket.my_bucket my-bucket-nameMoving resources within state (renamed resource blocks):
# If you renamed the resource block, use state mv instead of rm + import
# Old: resource "aws_s3_bucket" "old_name"
# New: resource "aws_s3_bucket" "new_name"
terraform state mv aws_s3_bucket.old_name aws_s3_bucket.new_name
# Updates state without touching the real resourceFix 5: Fix Config Drift After Import
After importing, terraform plan often shows changes because your config doesn’t fully match the actual resource. Align the config with the real state:
# Step 1: Import the resource
terraform import aws_s3_bucket.my_bucket my-bucket-name
# Step 2: See what Terraform wants to change
terraform plan
# Note every attribute it wants to change
# Step 3: Update your resource block to match current state
# Either: add the attributes to your config
# Or: accept the changes (Terraform will apply them on next apply)Example — fixing versioning drift:
# BEFORE — config doesn't specify versioning
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-bucket-name"
}
# terraform plan shows: ~ versioning { enabled = false -> true }
# AFTER — config matches actual state
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-bucket-name"
}
resource "aws_s3_bucket_versioning" "my_bucket" {
bucket = aws_s3_bucket.my_bucket.id
versioning_configuration {
status = "Enabled" # Matches what's actually in AWS
}
}
# terraform plan now shows: No changes.Note: AWS provider v4+ splits many S3 attributes into separate resources (
aws_s3_bucket_versioning,aws_s3_bucket_acl, etc.). Import each sub-resource separately.
Fix 6: Bulk Import with for_each
Import many similar resources at once using import blocks with for_each (Terraform 1.7+):
# Import multiple S3 buckets
locals {
buckets = {
"logs" = "my-logs-bucket-prod"
"backups" = "my-backups-bucket-prod"
"assets" = "my-assets-bucket-prod"
}
}
import {
for_each = local.buckets
id = each.value
to = aws_s3_bucket.buckets[each.key]
}
resource "aws_s3_bucket" "buckets" {
for_each = local.buckets
bucket = each.value
}terraform plan # Shows N imports
terraform apply # Imports all at onceStill Not Working?
Provider authentication — terraform import must be able to authenticate to the provider (AWS, GCP, Azure) to verify the resource exists. Run terraform init and ensure credentials are configured before importing.
Import ID requires sub-components — some resources have compound IDs. For example, aws_iam_role_policy_attachment requires role-name/policy-arn. Check the provider documentation’s “Import” section carefully.
Resource doesn’t support import — not every resource type supports terraform import. If a resource has no “Import” section in its docs, it can’t be imported. You’ll need to delete the real resource and recreate it with Terraform, or use terraform state to manually craft a state entry (advanced, error-prone).
Terraform Cloud / Enterprise — when using Terraform Cloud, run terraform import in a local workspace that mirrors the remote state, then push the state. Or use the Terraform Cloud API to run the import remotely.
For related Terraform issues, see Fix: Terraform Error Acquiring State Lock and Fix: Terraform Plan Error Invalid Reference.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Terraform Variable Not Set — No Value for Required Variable
How to fix Terraform 'no value for required variable' errors — variable definition files, environment variables, tfvars files, sensitive variables, and variable precedence.
Fix: Helm Not Working — Release Already Exists, Stuck Upgrade, and Values Not Applied
How to fix Helm 3 errors — release already exists, another operation is in progress, --set values not applied, nil pointer template errors, kubeVersion mismatch, hook failures, and ConfigMap changes not restarting pods.
Fix: nginx Upstream Load Balancing Not Working — All Traffic Hitting One Server
How to fix nginx load balancing issues — upstream block configuration, health checks, least_conn vs round-robin, sticky sessions, upstream timeouts, and SSL termination.
Fix: Terraform Error Acquiring State Lock — State Lock Conflict
How to fix Terraform state lock errors — understanding lock mechanisms, safely force-unlocking stuck locks, preventing lock conflicts in CI/CD, and using remote backends correctly.