Introduction

A Terraform migration can move state storage to a new backend while plans and applies still read from the old one. Infrastructure changes seem to succeed in one environment but not another, one pipeline locks the new state while another still references the retired backend, or drift appears only after the old storage account, bucket, or workspace is removed because backend settings, cached initialization data, and CI variables often lag behind the cutover.

Treat this as a state-path problem instead of a generic Terraform failure. Start by checking which backend endpoint, workspace, and state object an affected run actually uses, because migrations often validate the new backend once while day-to-day automation continues initializing against older backend metadata.

Symptoms

  • Terraform still uses the old remote state backend after migration
  • Plans or applies succeed locally but CI still references the retired backend
  • One workspace uses the new backend while another still locks or reads the previous one
  • State drift appears after the old bucket, container, or workspace is restricted
  • The new backend is healthy, but live runs never update state there
  • The issue started after moving Terraform state storage, CI pipelines, or backend credentials

Common Causes

  • Backend configuration still points to the old bucket, storage account, or workspace
  • Cached .terraform initialization data still preserves the previous backend target
  • CI variables or pipeline templates still inject old backend settings
  • One environment or workspace was reinitialized while another still uses the retired backend
  • Credentials or role bindings were updated for the new backend, but the actual backend address was not
  • Validation confirmed the new backend was reachable but did not verify where real plans and applies stored state

Step-by-Step Fix

  1. Capture one affected Terraform run and record the backend type, endpoint, workspace, and state object it actually uses, because the live state path determines where infrastructure truth is stored.
  2. Compare that active backend path with the intended post-migration design, because one stale backend block or pipeline variable can keep all changes tied to the retired state store.
  3. Review Terraform backend configuration, workspace selection, .terraform initialization data, and CI or secret-injection settings for references to the old backend, because Terraform state routing depends on local initialization and automation inputs together.
  4. Check each workspace, environment, and runner separately if behavior differs, because migrations often reinitialize one path while another still uses the previous backend metadata.
  5. Update the authoritative backend configuration and reinitialize affected runs so Terraform reads and writes state in the intended backend, because creating the new state store alone does not retarget existing working directories or pipelines.
  6. Run a controlled plan or state inspection and confirm the intended backend shows the expected lock or updated state data, because a successful Terraform command does not prove the right backend handled it.
  7. Verify the old backend no longer receives new locks, reads, or state updates from migrated runs, because split state ownership can remain hidden while both backends stay reachable.
  8. Review credentials, backend access policy, and workspace mapping if initialization still fails, because the destination can be correct while trust or permissions still block the new state path.
  9. Document which team owns backend configuration, runner templates, and migration validation so future Terraform cutovers verify the actual state backend before retiring the previous one.