hashicorp/terraform · warning
state is already unlocked
Error message
state is already unlocked
What it means
The Kubernetes backend's Unlock() found a lease whose HolderIdentity is nil, meaning the state is not currently held by anyone. Rather than silently succeeding, it returns this error so the caller knows the unlock was a no-op against an already-free state.
Source
Thrown at internal/backend/remote-state/kubernetes/client.go:312
return "", err
}
return info.ID, err
}
func (c *RemoteClient) Unlock(id string) error {
leaseName, err := c.createLeaseName()
if err != nil {
return err
}
lease, err := c.getLease(leaseName)
if err != nil {
return err
}
if lease.Spec.HolderIdentity == nil {
return fmt.Errorf("state is already unlocked")
}
lockInfo, err := c.getLockInfo(lease)
if err != nil {
return err
}
lockErr := &statemgr.LockError{Info: lockInfo}
if *lease.Spec.HolderIdentity != id {
lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
return lockErr
}
lease.Spec.HolderIdentity = nil
removeLockInfo(lease)
_, err = c.kubernetesLeaseClient.Update(context.Background(), lease, metav1.UpdateOptions{})
if err != nil {View on GitHub (pinned to c9def3e214)
Solutions
- Treat this as informational: the state is already unlocked, so no force-unlock is needed.
- Check whether another Terraform run or a teammate already unlocked the state.
- If the lease is in a bad state (e.g. stale lock-info annotation with nil holder), manually clear the annotation or delete the lease after confirming no active run holds it.
Defensive patterns
Strategy: type-guard
Validate before calling
// Before unlocking, check whether the lease still holds a lock
lease, err := c.getLease(name)
if err != nil { return err }
if lease.Spec.HolderIdentity == nil {
// nothing to unlock; treat as success
return nil
}
return c.Unlock(id) Type guard
func isLeaseHeld(lease *coordinationv1.Lease) bool {
return lease != nil && lease.Spec.HolderIdentity != nil
} Prevention
- Check the live lease holder before issuing an unlock.
- Avoid redundant/duplicate unlock calls after failures.
- Treat 'already unlocked' as benign, not an error to retry.
When it happens
Trigger: Calling Unlock(id) (client.go:300-336) when the lease exists but lease.Spec.HolderIdentity == nil, i.e. a previous unlock or external deletion already cleared the holder.
Common situations: A duplicate/late unlock after the state was already released; a manual edit of the lease removing HolderIdentity; an earlier failed init that partially unlocked; Terraform retrying an unlock after the lease was cleared by another process.
Related errors
- %v Additionally, unlocking the state in Kubernetes faile
- lock id %q does not match existing lock
- failed to lock inmem state: %s
- Failed to configure: %s
- secret_suffix must not end with '-<number>', got %q
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/ba9bce327ee2e6ab.
Report an issue: GitHub.