Skip to content
Latchkey

Terraform S3 Backend Missing DynamoDB Lock Table - Unsafe Concurrent Writes in CI

An S3 backend with no dynamodb_table (and no native lockfile) does not lock state. Two CI runs can write at once and clobber each other, corrupting or rolling back state.

What this error means

Parallel Terraform jobs both "succeed" but the resulting state is missing resources one of them created, or a later plan shows surprise re-creates. There was never an "Error acquiring the state lock" because nothing was enforcing a lock.

symptom
# No lock error is raised - that is the problem.
# Two concurrent applies each read state, mutate, and write back,
# and the last writer overwrites the other's changes:
#   run A: writes state v42 (adds aws_instance.web)
#   run B: writes state v42 (adds aws_db_instance.main), losing web

Common causes

No dynamodb_table configured on the S3 backend

Older S3 backends require dynamodb_table for locking. Omitting it (and not enabling the native S3 lockfile) means concurrent writes are not serialized.

Unserialized concurrent pipelines

Two PR pipelines, or a developer and CI, target the same state with no locking and no CI concurrency group, so writes race.

How to fix it

Enable locking on the S3 backend

Add a dynamodb_table (or, on newer Terraform, the native S3 lockfile) so concurrent writes are blocked.

backend.tf
terraform {
  backend "s3" {
    bucket         = "my-tf-state"
    key            = "app/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"   # enables locking
    # Terraform 1.10+: use_lockfile = true (native S3 lock)
  }
}

Serialize Terraform jobs as defense in depth

Add a CI concurrency group so two runs never target the same state simultaneously.

.github/workflows/ci.yml
concurrency:
  group: terraform-${{ github.ref }}
  cancel-in-progress: false

How to prevent it

  • Always configure locking (dynamodb_table or use_lockfile) on S3 backends.
  • Serialize Terraform jobs with a concurrency group.
  • Enable S3 versioning so a clobbered state can be recovered.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →