Fix Terraform State Lock Stuck After Failed Apply
The Error: Terraform State Lock Stuck
You run terraform plan or terraform apply and get:
Error: Error locking state: Error acquiring the state lock:
ConditionalCheckFailedException: The conditional request failed
Lock Info:
ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Path: s3://my-tf-state/prod/terraform.tfstate
Operation: OperationTypeApply
Who: runner@ci-node-05
Version: 1.7.3
Created: 2026-03-29 14:22:01.123456 +0000 UTC
The state file is locked by a previous operation that never released it — usually because terraform apply was interrupted by a CI timeout, killed process, or network failure.
Root Cause
Terraform acquires a lock before modifying state to prevent concurrent writes. With remote backends (S3+DynamoDB, Consul, Azure Blob), the lock is stored externally. If the process dies before releasing the lock, it remains indefinitely. Terraform will not proceed until the lock is cleared.
Step-by-Step Fix
1. Confirm the lock is genuinely orphaned
Check the lock info in the error message:
- Who: Which user or CI runner acquired the lock
- Created: When the lock was taken
- Operation: What was running (plan, apply, etc.)
Verify that no one is currently running Terraform against this state:
# Check if the process is still alive on the CI server
ssh ci-node-05 "ps aux | grep terraform"
# Check recent CI pipeline runs
# If the pipeline already finished or failed, the lock is orphaned
2. Force-unlock the state
Use the Lock ID from the error message:
terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890
Terraform will prompt for confirmation:
Do you really want to force-unlock?
Terraform will remove the lock on the remote state.
This will allow local Terraform commands to modify this state,
even though it may still be in use. Only do this if the
initialization to lock above failed.
Enter a value: yes
Type yes to confirm.
3. If force-unlock fails, clear the DynamoDB lock manually
For S3 backends with DynamoDB locking:
# Find the lock item
aws dynamodb get-item \
--table-name terraform-locks \
--key '{"LockID": {"S": "my-tf-state/prod/terraform.tfstate"}}' \
--region us-east-1
# Delete the lock item
aws dynamodb delete-item \
--table-name terraform-locks \
--key '{"LockID": {"S": "my-tf-state/prod/terraform.tfstate"}}' \
--region us-east-1
For Consul backends:
consul kv delete terraform-state/prod/.lock
4. Verify state integrity after unlocking
# Pull and inspect the state
terraform state pull | jq '.serial, .lineage'
# Run a plan to verify nothing is out of sync
terraform plan
If the interrupted apply partially completed, you may see drift. Review the plan carefully before applying.
5. Reconcile partial applies
If the failed apply created some resources but not others:
# Import resources that were created but not recorded in state
terraform import aws_instance.web i-0abc123def456
# Or refresh state to pick up real-world changes
terraform apply -refresh-only
Prevention Tips
- Set CI timeouts longer than your longest apply — a 10-minute timeout on a 15-minute apply guarantees orphaned locks.
- Use
-lock-timeoutto handle brief contention:terraform apply -lock-timeout=5m - Wrap applies in a trap in CI scripts to release the lock on failure:
cleanup() { terraform force-unlock -force "$LOCK_ID" 2>/dev/null; } trap cleanup EXIT terraform apply -auto-approve - Enable DynamoDB TTL on your lock table so stale locks expire automatically (set TTL to 1 hour).
- Centralize Terraform runs with Terraform Cloud, Spacelift, or Atlantis — they manage locking and prevent collisions automatically.
Was this article helpful?
SRE & Observability Engineer
If it's not measured, it doesn't exist. SLO-driven, metrics-obsessed, and the person who gets paged at 3 AM so you don't have to. Observability isn't optional.
Related Articles
Terraform "Error: No Valid Credential Sources Found" On AWS — Fixing Authentication And Provider Configuration Issues
If you've spent any time with Terraform and AWS, you've almost certainly run into this gem at some point: It's one of those errors that looks simple but ca...
Terraform "Error: Cycle" In Resource Dependencies — How To Detect And Break Circular References
If you've spent any meaningful time with Terraform, you've probably encountered this at the worst possible moment: Everything was working fine, you added o...
Terraform Error: Invalid For_each Argument Must Be A Map Or Set Of Strings - Complete Fix Guide
If you've been working with Terraform's `for_each` argument, you've probably hit this error at least once. Don't worry – it's one of those frustrating but...
Fix Terraform 'Error Acquiring the State Lock' with DynamoDB
Resolve Terraform DynamoDB state lock errors caused by permission issues, missing tables, or misconfigured backends.
Terraform Dynamic Blocks For Managing Variable Infrastructure Resources
If you've been working with Terraform for a while, you've probably hit that wall where you need to create resources with configurations that vary based on...
Writing Reusable Terraform Modules: A Practical Guide
Learn how to write Terraform modules that are actually reusable — with input validation, sensible defaults, and clean interfaces across environments.
More in Terraform
View all →Terraform CLI: Cheat Sheet
Terraform CLI cheat sheet with commands organized by workflow — init, plan, apply, destroy, state manipulation, imports, and workspace management.
Terraform from Zero to Production: Project Structure, Modules, State, and CI/CD
Build production-grade Terraform infrastructure — project structure, module design, state management, testing, and CI/CD pipeline integration.
Testing Terraform with Terratest: A Practical Guide
How to write unit and integration tests for Terraform modules using Terratest — because untested infrastructure is a liability.
Terraform Module Design Patterns for Large Teams
Battle-tested Terraform module patterns for teams — from file structure to versioning to composition. If it's not in code, it doesn't exist.