D

Terraform Troubleshooting

Diagnose and recover from state locks, drift, corrupted state and failed applies.

Updated 2026-09-03

On this page

Most Terraform incidents are state problems, not configuration problems. Work through these in order before reaching for anything destructive.

State Lock

Terraform locks state before any operation that could write to it, to stop two applies from racing. A lock survives its owning process crashing (Ctrl-C during apply, a killed CI job), leaving state locked with nothing actually running.

Confirm nothing is actually running

Check CI for an in-progress or recently killed run, and ask the team before assuming the lock is stale — force-unlocking a lock held by a genuinely running apply can corrupt state.

Read the lock error for the lock ID

Error: Error acquiring the state lock
 
Lock Info:
  ID:        5c4c02f4-1234-5678-90ab-cdef01234567
  Path:      env:/prod/terraform.tfstate
  Operation: OperationTypeApply
  Who:       ci-runner@build-042

Force-unlock using that ID

terraform force-unlock 5c4c02f4-1234-5678-90ab-cdef01234567
destructive

Releases the lock. Only run this after confirming the operation that created it is genuinely dead — not just slow.

Corrupted or Out-of-Sync State

Pull state and inspect it

terraform state pull

Downloads the raw state JSON so you can inspect it directly, or diff it against a known-good backup.

Check for drift before touching anything

terraform plan -refresh-only

Shows what's actually different between state and real infrastructure, without writing anything.

Restore from backup if state is genuinely corrupted

Terraform writes a terraform.tfstate.backup before most operations that modify state. If a bad push or an interrupted apply corrupted the current state file, this is usually the fastest recovery path.

terraform state push terraform.tfstate.backup
destructive

Overwrites remote state with the local backup file. Confirm the backup is actually newer and correct before pushing — this replaces the team's source of truth.

Backend Changed Unexpectedly

terraform init -reconfigure

Re-points Terraform at the backend defined in configuration, discarding any stale cached backend settings, without attempting to migrate old state.

Two backends, two states

If a teammate changed the backend block and ran init -migrate-state locally without telling anyone, there may now be two separate state files. Confirm which one is authoritative with terraform state list on each before writing to either.

Resource Already Exists

Error: A resource with the ID ... already exists means the resource is real, but not in Terraform's state — usually created manually, or previously managed by a different state file.

terraform import aws_instance.example i-0123456789abcdef0

Brings the existing resource under management instead of trying to recreate it. Requires a matching resource block in configuration first.

Provider Version Problems

terraform init -upgrade

Re-resolves provider versions against your version constraints, picking up newer releases within them.

Pin, don't chase

Pin provider versions with a required_providers block and a committed .terraform.lock.hcl. Most "it worked yesterday" incidents are an unpinned provider picking up a breaking minor release.

Dependency and Ordering Failures

If apply fails partway through, Terraform's graph means some resources are created and others aren't — state now reflects reality for what succeeded. Re-running apply is almost always correct: Terraform re-plans from the current state and only acts on what's still needed. Resist the urge to manually edit state to "fix" a partial apply.

Never hand-edit the state file

Editing terraform.tfstate directly is unsupported and easy to get subtly wrong — a malformed field or a stale serial number can make future applies mis-diff every resource in it. Use terraform state subcommands instead; they update the file safely.