## TL;DR

The object in S3 at your state key is not valid state: it got corrupted, overwritten with something else, or truncated. If the bucket has versioning (it should), restore the last good version and push it back. Last resort: rebuild state with `import`.

## The error

```text
Error: state data in S3 does not have the expected content
```

## Steps to fix

1. List versions of the state object:
   ```bash
   aws s3api list-object-versions --bucket my-terraform-state --prefix terraform.tfstate
   ```
   - Expected: you see previous versions with timestamps.
2. Download the last good version:
   ```bash
   aws s3api get-object --bucket my-terraform-state --key terraform.tfstate \
     --version-id [VERSION_ID] terraform.tfstate.backup
   ```
   - Expected: a local file that parses as JSON with a `serial` and `resources`.
3. Push it back:
   ```bash
   terraform state push terraform.tfstate.backup
   ```
   - Expected: state restored; `terraform plan` runs clean.
4. Last resort if no good version exists: `terraform import` each resource back into a fresh state.
   - Expected: slow but complete recovery.

## When to use this

- `plan`/`apply`/`init` fails with `state data in S3 does not have the expected content` on a previously working S3 backend.

## When NOT to use this

- `403` errors are permissions. `state snapshot was created by Terraform vX` is version skew. If the bucket has no versioning and no good copy, skip to the import rebuild.

## Compatibility

- All Terraform versions with the S3 backend. Requires bucket versioning for the easy path.

## Root cause

Something wrote non-state bytes to the state key: a crashed or partial upload, a script writing logs to the wrong key, or an external process overwriting it. Terraform validates the object's shape on read and refuses to proceed rather than plan against garbage.

## Edge cases

- Enable S3 versioning on every state bucket; without it, this error is much harder to recover from.
- `terraform state push` of a stale backup can fork state if someone applied in between; coordinate with the team.
- SSE-KMS key deletion makes state unreadable with a different error; check the key still exists.