hashicorp/terraform · error · statemgr.LockError
lock id %q does not match existing lock
Error message
lock id %q does not match existing lock
What it means
Raised in RemoteClient.Unlock (client.go:282-284). For safety, Unlock compares the lock ID passed in against the ID stored in the blob lock metadata; if they differ, it refuses to release someone else's lease and returns a LockError. This prevents one Terraform run from unlocking state held by a different run.
Source
Thrown at internal/backend/remote-state/azure/client.go:283
MetaData: blob.MetaData,
}
_, err = c.giovanniBlobClient.SetMetaData(ctx, c.containerName, c.keyName, opts)
return err
}
func (c *RemoteClient) Unlock(id string) error {
lockErr := &statemgr.LockError{}
lockInfo, err := c.getLockInfo()
if err != nil {
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
return lockErr
}
lockErr.Info = lockInfo
if lockInfo.ID != id {
lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
return lockErr
}
c.leaseID = lockInfo.ID
if err := c.writeLockInfo(nil); err != nil {
lockErr.Err = fmt.Errorf("failed to delete lock info from metadata: %s", err)
return lockErr
}
ctx := newCtx()
_, err = c.giovanniBlobClient.ReleaseLease(ctx, c.containerName, c.keyName, blobs.ReleaseLeaseInput{LeaseID: id})
if err != nil {
lockErr.Err = err
return lockErr
}
c.leaseID = ""
View on GitHub (pinned to c9def3e214)
Solutions
- Use the correct lock ID shown by the current 'terraform' error or by querying the blob lock metadata
- If you are certain the lock is stale, break the lease directly: az storage blob lease break --account-name <account> -c <container> -b <key>
- Inspect current lock info: az storage blob metadata show / az storage blob lease show
Example fix
# before: wrong/stale lock id terraform force-unlock 00000000-0000-0000-0000-000000000000 # -> 'lock id does not match existing lock' # after: read the actual stored lock id from metadata, or break the lease az storage blob lease break \ --account-name mystage --auth-mode login \ -c tfstate -b "prod.terraform.tfstate" terraform init
Defensive patterns
Strategy: validation
Validate before calling
# Validate the lock id matches the stored metadata before force-unlock
STORED=$(az storage blob metadata show --account-name "$ARM_STORAGE_ACCOUNT_NAME" -c "$ARM_CONTAINER_NAME" -n "$ARM_KEY" --query 'terraformlockid' -o tsv 2>/dev/null | base64 -d 2>/dev/null | grep -oE '"ID":"[0-9a-f-]{36}"' | grep -oE '[0-9a-f-]{36}')
[ "$STORED" = "$1" ] && echo "OK: id matches" || echo "FAIL: id mismatch (157); stored=$STORED supplied=$1"
# usage: validate_lock_id "$PROPOSED_LOCK_ID" Prevention
- Always copy the lock ID from the current Terraform error, not an old log
- If you cannot recover the correct ID, break the lease at the Azure layer
- Avoid force-unlocking state you do not own to prevent unlocking another run's lock
When it happens
Trigger: Produced at client.go:282-283 when lockInfo.ID != id during Unlock. Happens when a stale or wrong lock ID is passed to 'terraform force-unlock', or when Terraform's recorded lock ID no longer matches the actual lease holder.
Common situations: Running 'terraform force-unlock' with the wrong ID (a typo, or an old ID from a previous run); two runs interfering; the lease ID changed because someone already broke/reacquired the lease.
Related errors
- failed to retrieve lock info: %s
- failed to delete lock info from metadata: %s
- failed to lock azure state: %s
- Error unlocking Azure state. Lock ID: %s Error: %s You may
- state blob is already locked
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/a42f74aaa28cebe4.
Report an issue: GitHub.