# Fix terraform "Error: Failed to save state"

**TL;DR:** Your apply did its work, but Terraform could not write the new state to the backend. Do not just re-apply: Terraform already wrote the state to `errored.tfstate` in your working directory. Fix the underlying backend problem (lock conflict, permissions, deleted bucket, network), then push the saved state with `terraform state push errored.tfstate`.

## The error

```text
Error: Failed to save state: ConditionalCheckFailedException
```

## Steps

1. Read the full error: the line after names the cause (lock conflict, `AccessDenied` on `s3:PutObject`, `NoSuchBucket`, network failure). Expected: you know which backend problem to fix.
2. If it is a lock conflict (`ConditionalCheckFailedException`), check for a concurrent run. Wait for it to finish; only `force-unlock` if you are certain the holder is dead. Expected: no two writers remain.
3. If it is permissions, grant the identity `s3:PutObject` (and friends) on the bucket and `bucket/*`. If the bucket is gone, recreate it. Expected: the backend is writable again.
4. Push the rescued state: `terraform state push errored.tfstate`. Expected: the backend accepts the state and a follow-up `plan` is clean.
5. Delete `errored.tfstate` only after the push succeeds and you have verified with `terraform plan`. Expected: no forked state.

## When this applies

- `apply` ends with "Failed to save state" (often followed by "Failed to persist state to backend" and the `errored.tfstate` recovery note).
- The infrastructure changes actually happened; only the state write failed.

## When it does NOT apply

- "Failed to persist state to backend" as the headline without a preceding save error. That is the follow-on message; treat the root save error above it.
- State read errors at plan time. Those happen before any changes, so there is nothing to rescue.

## Tool and version compatibility

- Terraform CLI 0.12+ through 1.x, any backend with locking (S3, GCS, AzureRM, Terraform Cloud).

## Why it happens

The state write is conditional on still holding the lock and on the backend accepting the write. A conflicting writer, an expired lock, a revoked permission, or a deleted bucket all abort the save after the cloud changes are already done. Terraform writes `errored.tfstate` locally so the result is recoverable instead of lost.

## Edge cases and pitfalls

- Re-running `apply` before pushing `errored.tfstate` creates a forked state: the backend still has the old state, your next apply plans against it, and recovery gets much harder.
- The lock may or may not have released. Check with a fresh `plan`; if it complains about the lock, deal with that first.