criticalIntermediateSymptom-first#state#lock#dynamodb#backend

State lock held — error acquiring the state lock

Error acquiring the state lock: Error message: ConditionalCheckFailedException

Likely source:availabilityconfiguration

Focused incident mode — strips away everything but this runbook.

Symptoms

  • Error acquiring the state lock: Error message: ConditionalCheckFailedException
  • terraform apply or plan hangs waiting for lock
  • DynamoDB item with LockID still present after a crash

Never force-unlock while an active apply is writing real infrastructure. Always confirm the lock owner is dead first.

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Lock error output

    terraform apply 2>&1 | head -20
  • DynamoDB lock entry

    aws dynamodb get-item --table-name <TABLE> --key '{"LockID":{"S":"<BUCKET>/<KEY>"}}'

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • terraform apply was killed mid-run (SIGTERM, OOM, CI timeout)
  • DynamoDB LockID item still exists with an old timestamp
  • No active process matches the lock owner

Confirm before fixing

aws dynamodb get-item --table-name <TABLE> --key '{"LockID":{"S":"<BUCKET>/<KEY>"}}'
READ

Read lock metadata

Expected: Lock item present with stale Info/Who

Fix

terraform force-unlock <LOCK_ID>
CHANGE

Force-unlock the orphaned lock

Expected: Lock released successfully

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
terraform force-unlock <LOCK_ID>
CHANGE

Release the stale lock (after verifying no live apply is running)

2
terraform plan
READ

Verify state access is restored

Prevention

  • Set CI pipeline timeouts shorter than the DynamoDB TTL (default 10 minutes).
  • Use terraform init -lock-timeout=300s to fail loudly instead of hanging forever.
  • Run terraform force-unlock in a cleanup step on CI failure/timeout.
  • Monitor DynamoDB TTL deletions and alert on stale locks.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.