Skip to content

Fix: Terraform Error locking state: Error acquiring the state lock

FixDevs ·

Quick Answer

How to fix Terraform state lock error caused by concurrent runs, crashed operations, DynamoDB lock table issues, and stale lock IDs.

The Error

You run terraform plan or terraform apply and get:

Error: Error locking state: Error acquiring the state lock

Error message: ConditionalCheckFailedException: The conditional request failed
Lock Info:
  ID:        abcd1234-ef56-7890-abcd-ef1234567890
  Path:      my-project/terraform.tfstate
  Operation: OperationTypeApply
  Who:       user@hostname
  Version:   1.7.0
  Created:   2024-01-15 10:30:00.000000000 +0000 UTC
  Info:

Terraform acquires a state lock to protect against two processes writing
to the state at the same time. This error means Terraform could not
acquire the lock.

Terraform cannot acquire the state lock because another process is already holding it. The lock prevents concurrent state modifications that could corrupt the state file.

Why This Happens

Terraform uses state locking to ensure only one person or process modifies infrastructure at a time. When using a remote backend (S3 + DynamoDB, Terraform Cloud, GCS, etc.), a lock entry is created before any state-modifying operation.

Common causes:

  • Another terraform apply is running. A teammate or CI/CD pipeline is actively applying changes.
  • Previous operation crashed. A terraform apply was interrupted (Ctrl+C, network failure, timeout) and the lock was not released.
  • CI/CD pipeline timeout. A pipeline ran terraform apply but timed out before completion, leaving the lock.
  • DynamoDB table issue. The lock table does not exist, has wrong permissions, or the lock entry is stale.
  • Terraform Cloud workspace locked. Someone locked the workspace manually or a run is queued.

Fix 1: Wait for the Other Operation

Check if another operation is genuinely running. The error shows Who: (the user) and Created: (when the lock was acquired).

If the lock was created minutes ago by a teammate, wait for their operation to finish:

# Check with your team
# Or look at CI/CD pipeline status

If the lock is recent and the Who: field shows a valid user or CI system, do not force-unlock — wait for the operation to complete.

Fix 2: Force Unlock a Stale Lock

If the lock is stale (the operation crashed, the CI pipeline timed out, or the user confirmed they are not running anything):

terraform force-unlock LOCK_ID

Use the Lock ID from the error message:

terraform force-unlock abcd1234-ef56-7890-abcd-ef1234567890

Terraform asks 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 'yes' will be accepted to confirm.

Type yes to confirm.

Warning: Only force-unlock if you are certain no other operation is running. Force-unlocking while another process is actively modifying state can corrupt the state file.

Pro Tip: Before force-unlocking, check if the user listed in Who: is still running Terraform. Ask them directly. If the lock was created by a CI/CD system, check the pipeline status. A stale lock from a crashed pipeline is safe to force-unlock; a lock from an in-progress pipeline is not.

Fix 3: Fix DynamoDB Lock Table (AWS S3 Backend)

For S3 backends, the lock is stored in a DynamoDB table. If the table does not exist or is misconfigured:

Create the lock table:

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

Backend configuration:

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "project/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

Check the table exists and has the right schema:

aws dynamodb describe-table --table-name terraform-locks

The table must have a string hash key named LockID.

Check DynamoDB permissions:

Your IAM user or role needs dynamodb:GetItem, dynamodb:PutItem, dynamodb:DeleteItem on the lock table:

{
  "Effect": "Allow",
  "Action": [
    "dynamodb:GetItem",
    "dynamodb:PutItem",
    "dynamodb:DeleteItem"
  ],
  "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/terraform-locks"
}

For IAM permission issues in general, see Fix: AWS AccessDeniedException.

Fix 4: Manually Remove a Stale DynamoDB Lock

If terraform force-unlock does not work, remove the lock entry directly from DynamoDB:

aws dynamodb delete-item \
  --table-name terraform-locks \
  --key '{"LockID": {"S": "my-project/terraform.tfstate"}}'

Or use the DynamoDB console:

  1. Go to DynamoDB → Tables → terraform-locks → Explore table items
  2. Find the item with LockID matching your state file path
  3. Delete the item

Then retry your Terraform command.

Warning: Directly deleting DynamoDB items bypasses Terraform’s safety checks. Only do this when terraform force-unlock fails.

Fix 5: Fix Terraform Cloud Locks

If using Terraform Cloud or Terraform Enterprise:

Check the workspace:

  1. Go to Terraform Cloud → Workspaces → Your workspace
  2. Check for running or queued plans/applies
  3. If a run is stuck, click “Discard run”

Unlock the workspace:

  1. Go to Workspace → Settings → General
  2. Click “Force Unlock” (requires admin permissions)

Via API:

curl -s \
  --header "Authorization: Bearer $TFC_TOKEN" \
  --header "Content-Type: application/vnd.api+json" \
  --request POST \
  "https://app.terraform.io/api/v2/workspaces/$WORKSPACE_ID/actions/force-unlock"

Common Mistake: Running terraform apply locally when the workspace is configured for remote execution. The local run acquires a lock that conflicts with the remote execution. Use terraform cloud for remote execution or configure execution_mode = "local" in the workspace settings.

Fix 6: Prevent Lock Issues in CI/CD

Configure your CI/CD pipeline to handle locks gracefully:

GitHub Actions:

jobs:
  terraform:
    runs-on: ubuntu-latest
    concurrency:
      group: terraform-${{ github.ref }}
      cancel-in-progress: false  # Don't cancel — let it finish
    steps:
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform apply -auto-approve
        timeout-minutes: 30

concurrency ensures only one Terraform job runs at a time per branch.

Add timeouts:

- run: terraform apply -auto-approve
  timeout-minutes: 30

This kills the job after 30 minutes, but the lock might still be held. Add cleanup:

- run: terraform apply -auto-approve
  timeout-minutes: 30
  continue-on-error: true

- run: terraform force-unlock -force $LOCK_ID || true
  if: failure()

Use -lock-timeout:

terraform apply -lock-timeout=5m

This waits up to 5 minutes for the lock to become available before failing. Useful when multiple pipelines might run close together.

Fix 7: Fix State File Corruption

If the state file is corrupted (maybe from a force-unlock during an active write), restore from backup:

S3 versioning:

# List state file versions
aws s3api list-object-versions --bucket my-terraform-state --prefix project/terraform.tfstate

# Restore a previous version
aws s3api get-object --bucket my-terraform-state --key project/terraform.tfstate --version-id VERSION_ID terraform.tfstate.backup

Pull the current state:

terraform state pull > current-state.json

Check if the state is valid JSON. If not, restore from the backup.

Push a fixed state:

terraform state push terraform.tfstate.backup

For the general state lock error article, see Fix: Terraform error acquiring state lock.

Fix 8: Use State Lock Alternatives

Disable locking (not recommended):

terraform apply -lock=false

This bypasses locking entirely. Only use this as a last resort for debugging. Running without locks in a team environment can corrupt the state file.

Use local state (for solo development):

terraform {
  backend "local" {
    path = "terraform.tfstate"
  }
}

Local backends still use file-system locks but do not have DynamoDB or network-related lock issues.

Still Not Working?

Check for network issues. If Terraform cannot reach DynamoDB or Terraform Cloud, it cannot acquire or release locks. Check your network connectivity and VPN status.

Check for AWS region mismatch. The DynamoDB table must be in the same region specified in the backend configuration. A mismatch causes lock acquisition failures.

Check for IAM session expiration. If your AWS session token expired during a long terraform apply, the lock release fails. Use longer session durations for Terraform operations.

Check for S3 bucket access. If Terraform cannot read/write the state file in S3, it fails before attempting the lock:

aws s3 ls s3://my-terraform-state/project/

For Terraform provider installation failures, see Fix: Terraform failed to install provider.

Consider using OpenTofu if you need open-source Terraform. OpenTofu is a fork that uses the same state format and locking mechanisms.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles