This error occurs when Terraform cannot acquire a lock on your state file, typically due to a previous incomplete operation or concurrent access. It happens most often with S3 backends using DynamoDB for state locking.
Fixes ConditionalCheckFailedException
ps aux | grep terraformps aux | grep terraformError locking state: Error acquiring the state lock: ConditionalCheckFailedException
Terraform uses state locking to prevent multiple processes from modifying the state file simultaneously, which could cause corruption. The ConditionalCheckFailedException error indicates that the conditional check for acquiring a lock failed—usually because another process already holds the lock or a previous operation was interrupted before releasing it. This is commonly seen when using S3 backends with DynamoDB for state management, where Terraform attempts to write a new lock record under the condition that one doesn't already exist.
Before forcing an unlock, confirm that no Terraform operations are currently in progress. Check for hanging processes:
On Linux/Mac:
ps aux | grep terraformOn Windows (PowerShell):
Get-Process terraform* -ErrorAction SilentlyContinueIf you find active processes, allow them to complete naturally. If they're hung, kill them only after confirming no one else is using Terraform:
kill -9 <process_id>Terraform provides the Lock ID in the error message. Use this to force-unlock the state:
terraform force-unlock <LOCK_ID>Example:
terraform force-unlock 49b6e22e-1234-5678-90ab-3e3097cf95d4WARNING: Only force-unlock if you are absolutely certain no other process holds the lock. Forcing an unlock while another process is writing state will corrupt it.
If you receive a permission error, verify your AWS IAM user has the required permissions for DynamoDB lock management:
{
"Effect": "Allow",
"Action": [
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/terraform-locks"
}Also ensure you have the correct S3 permissions for your state file:
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::your-bucket/path/terraform.tfstate*"
}If terraform force-unlock doesn't work, you can manually remove the lock from DynamoDB using the AWS CLI:
List current locks:
aws dynamodb scan --table-name terraform-locks --region us-east-1Delete a specific lock:
aws dynamodb delete-item \
--table-name terraform-locks \
--key '{"LockID": {"S": "your-bucket/path/terraform.tfstate"}}' \
--region us-east-1Replace terraform-locks with your actual DynamoDB table name and update the S3 path accordingly.
After releasing the lock, retry your Terraform operation:
terraform plan
terraform applyOptionally, use a lock timeout to prevent this issue from repeating:
terraform plan -lock-timeout=10m
terraform apply -lock-timeout=15mThis gives concurrent operations up to 10-15 minutes to complete before timing out.
S3-Native State Locking (Terraform 1.11+): Starting with Terraform 1.11.0, S3-native state locking is generally available as a replacement for DynamoDB-based locking. If you're experiencing frequent lock issues with DynamoDB, consider migrating to S3-native locking by updating your backend configuration and removing the DynamoDB table. This eliminates an external dependency and simplifies lock management.
Lock Timeout Defaults: By default, Terraform waits 10 seconds to acquire a lock before failing. Increasing the -lock-timeout value (e.g., to 30s or 1m) can help with transient network issues or slow backends.
Production Safety: In production environments, always prefer terraform force-unlock over -lock=false. The latter bypasses locking entirely and risks concurrent state modifications. Only use -lock=false for emergency reads (e.g., terraform state list -lock=false).
Preventing Future Occurrences: Implement graceful shutdown handlers in CI/CD pipelines to ensure Terraform releases locks properly. Avoid using kill -9 for Terraform processes; instead, use SIGTERM to allow cleanup. Set reasonable timeouts in your CI/CD configuration (e.g., 30 minutes for apply operations) to catch hung processes early.