TL;DR
Run one of these depending on what you changed:
# Bucket or key path changed? Move the state.
terraform init -migrate-state
# Only credentials or minor settings changed? Just update the config.
terraform init -reconfigure
Pick -migrate-state when the bucket or path changed. Pick -reconfigure when only credentials or non-critical settings changed and the state is already where it should be.
What Triggers This Error
Terraform stores a hash of your backend config inside .terraform/terraform.tfstate. On every terraform init, it compares what's in your *.tf files against that cached hash. If they don't match, Terraform stops โ it doesn't silently proceed. That's intentional. Pointing at the wrong state bucket by accident would be catastrophic, so Terraform makes you explicitly confirm the change.
Common scenarios that trigger it:
- Changed the S3 bucket name or GCS bucket
- Changed the
key(path) inside the bucket - Switched AWS region for the S3 backend
- Renamed or switched workspaces that affect the backend path
- Pulled someone else's code where the backend config differs from your local cache
- Switched from a local backend to S3/GCS (or vice versa)
Fix 1: Migrate State to the New Backend
Changed where your state lives? This is the command you want:
terraform init -migrate-state
Here's what happens under the hood:
- Terraform connects to the old backend and reads the existing state
- It writes that state to the new backend location
- It asks for confirmation before doing anything
The prompt looks like this:
Initializing the backend...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "s3" backend to the
newly configured "s3" backend. No existing state was found in the newly
configured "s3" backend. Do you want to copy this state to the new backend?
Enter a value: yes
Type yes and Terraform handles the rest.
Fix 2: Reconfigure Without Migrating
Sometimes the backend config changed, but the state itself is already in the right place. Maybe you rotated credentials, updated your AWS CLI profile name, or tweaked a parameter that has nothing to do with where state is stored. In that case:
terraform init -reconfigure
This updates the local cache hash without touching the state at all. Fast and non-destructive.
Warning: Don't reach for -reconfigure if you actually changed the bucket name or key path. Your state will point to the wrong location and plan or apply will give you confusing โ potentially dangerous โ results.
Common Scenario: Switching S3 Bucket or Key
Before (old config):
terraform {
backend "s3" {
bucket = "my-tf-state-old"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
After (new config):
terraform {
backend "s3" {
bucket = "my-tf-state-new"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
Run:
terraform init -migrate-state
Before you do โ confirm you have read access to the old bucket and write access to the new one. Missing either permission will cause the migration to fail mid-copy.
Common Scenario: GCS Backend Change
terraform {
backend "gcs" {
bucket = "my-project-tf-state"
prefix = "terraform/state"
}
}
Changed the bucket or prefix? Same fix:
terraform init -migrate-state
GCS migration follows the same pattern โ Terraform reads from the old GCS location, writes to the new one. No extra steps needed.
Edge Case: Backend Config in Partial Config Files
Some teams skip hardcoding backend values and pass them at init time instead:
terraform init \
-backend-config="bucket=my-tf-state" \
-backend-config="key=prod/terraform.tfstate" \
-backend-config="region=us-east-1"
Or via a backend.hcl file:
# backend.hcl
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
terraform init -backend-config=backend.hcl
If that file changed, you'll hit the same error. Fix: add -migrate-state or -reconfigure to the same command:
terraform init -backend-config=backend.hcl -migrate-state
Verifying the Fix
After init completes, two quick checks tell you whether the migration actually worked:
# Should return your expected resources
terraform state list
# Should show no unexpected changes
terraform plan
If state list returns your resources, you're good. If it returns nothing when you expected dozens of resources, the state didn't migrate โ check IAM permissions on the bucket and re-run terraform init -migrate-state.
Prevention Tips
Backend changes cause the most pain when they happen silently mid-sprint. A few habits cut that risk significantly:
- Commit your
backend.hclor backend block alongside any infrastructure changes. Don't change backend config in isolation without telling the team first. - Make sure
.terraform/is in your.gitignoreโ it usually is, but double-check. Committing the cached backend hash breaks every teammate who pulls your code. - Before touching a backend, snapshot your state:
terraform state pull > backup-$(date +%Y%m%d).tfstate. Takes 2 seconds, saves hours if something goes wrong. - If your backend config lives in YAML-based CI variables, the YAML โ JSON Converter on ToolCraft is handy for validating config structure before it hits your pipeline โ runs entirely in the browser, nothing leaves your machine.
Quick Decision Tree
- Changed bucket name or key path? โ
terraform init -migrate-state - Changed credentials, profile, or minor settings only? โ
terraform init -reconfigure - Pulled someone else's code and your local cache is stale? โ
terraform init -reconfigure(assuming the remote backend itself didn't change) - Switching from local backend to remote for the first time? โ
terraform init -migrate-stateto upload your local state file to the remote backend

