TL;DR: A previous run crashed without releasing the state lock. Confirm nobody is actually applying right now, then `tofu force-unlock` with the lock ID from the error. Don't hand-delete the lock record unless force-unlock refuses.

```text
Error acquiring the state lock

Error message: ConditionalCheckFailedException: ...
Lock Info:
  ID:        1a2b3c4d-5e6f-7890-abcd-ef1234567890
  Path:      ...
  Operation: OperationTypeApply
  Who:       ci-runner-3@...
  Created:   2026-09-30 14:22:10 +0000 UTC
```

## Steps

1. Make sure nobody is actually applying: check CI, ask the team, look for a running tofu process.
   Expected: the lock holder is dead (crashed CI job, killed terminal).
2. Copy the lock ID from the error and run: `tofu force-unlock 1a2b3c4d-5e6f-7890-abcd-ef1234567890`.
   Expected: `Terraform state has been unlocked.`
3. Re-run your command.
   Expected: it acquires the lock and proceeds.

## When this applies

- `Error acquiring the state lock` with a lock ID and a `Created` timestamp from a run that is no longer alive.
- After a crashed CI job, killed terminal, or OOM'd apply.

## When it doesn't apply

- Someone IS applying right now: wait. Force-unlocking a live apply can corrupt state; two writers is exactly what the lock prevents.
- No lock ID in the error: that's a backend permissions problem, not a stale lock.

## Tool versions

All OpenTofu versions (DynamoDB/native-lock backends).

## Why it happens

The backend lock is a lease, not a heartbeat: if the holder dies without releasing it, the lease record stays until a human removes it. `force-unlock` is the supported removal; it verifies the ID so you can't release a lock you didn't read.

## Edge cases

- In CI, make the apply step trap failures and always release; better, use a lock timeout (`-lock-timeout`) so short stalls don't fail the run.
- Never delete the DynamoDB lock item by hand as a first resort; a typo'd key condition can orphan the real lock.