hashicorp/terraform · error
Error unlocking Azure state. Lock ID: %s Error: %s You may
Error message
Error unlocking Azure state. Lock ID: %s Error: %s You may have to force-unlock this state in order to use it again.
What it means
During StateMgr init, after acquiring a lease to create a new state blob, if a subsequent step (RefreshState/WriteState/PersistState) fails the backend tries to release the lease via lockUnlock -> stateMgr.Unlock. If that Unlock itself fails, this formatted error (errStateUnlock constant, backend_state.go:170-176) is returned, telling the user the state is still locked and must be force-unlocked. It is a recovery-path failure that leaves state locked on purpose for safety.
Source
Thrown at internal/backend/remote-state/azure/backend_state.go:125
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
return nil, diags.Append(err)
}
//if this isn't the default state name, we need to create the object so
//it's listed by States.
if v := stateMgr.State(); v == nil {
// take a lock on this state while we write it
lockInfo := statemgr.NewLockInfo()
lockInfo.Operation = "init"
lockId, err := client.Lock(lockInfo)
if err != nil {
return nil, diags.Append(fmt.Errorf("failed to lock azure state: %s", err))
}
// Local helper function so we can call it multiple places
lockUnlock := func(parent error) error {
if err := stateMgr.Unlock(lockId); err != nil {
return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
}
return parent
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, diags.Append(err)
}
//if this isn't the default state name, we need to create the object so
//it's listed by States.
if v := stateMgr.State(); v == nil {
// If we have no state, we have to create an empty state
if err := stateMgr.WriteState(states.NewState()); err != nil {
err = lockUnlock(err)
return nil, diags.Append(err)
}
if err := stateMgr.PersistState(nil); err != nil {View on GitHub (pinned to c9def3e214)
Solutions
- Run 'terraform force-unlock <lock-id>' using the Lock ID printed in the message to release the stuck lease
- If force-unlock fails, break the lease in Azure: az storage blob lease break --account-name <account> -c <container> -b <key>
- Re-run 'terraform init' then the original command after unlocking
- Investigate the root write failure that triggered the unlock path
Example fix
# the message includes the Lock ID to force-unlock terraform force-unlock <Lock-ID-from-error> # then re-run terraform init terraform apply
Defensive patterns
Strategy: try-catch
Validate before calling
# Detect a stuck lease from the failed-unlock flow before re-running
LID=$(terraform force-unlock -force 2>&1 | grep -oE '[0-9a-f-]{36}' | head -1)
az storage blob lease status --account-name "$ARM_STORAGE_ACCOUNT_NAME" -c "$ARM_CONTAINER_NAME" -n "$ARM_KEY" 2>/dev/null Try / catch
# The error embeds the Lock ID; capture and force-unlock, then break lease as fallback
recover_stuck_lock() {
LID=$(grep -oE 'Lock ID: [0-9a-f-]{36}' err.log | grep -oE '[0-9a-f-]{36}' | head -1)
terraform force-unlock -force "$LID" 2>/dev/null || \
az storage blob lease break --account-name "$ARM_STORAGE_ACCOUNT_NAME" -c "$ARM_CONTAINER_NAME" -n "$ARM_KEY"
} Prevention
- Always read the Lock ID from the message before force-unlocking
- If force-unlock itself fails, break the lease at the Azure layer as the fallback
- Investigate the original write failure that triggered the unlock path
When it happens
Trigger: Produced at backend_state.go:123-127 inside the lockUnlock closure when stateMgr.Unlock(lockId) returns an error during the new-state initialization flow (the v == nil branch at line 113). The lease was acquired but the cleanup unlock failed.
Common situations: The write failed due to a data-plane error and then the unlock also hit a transient network error; the lease expired or was broken by another process between lock and unlock; the lock metadata write (SetMetaData) failed (error 158) making Unlock return a LockError.
Related errors
- failed to lock azure state: %s
- state blob is already locked
- blob metadata %q was empty
- failed to retrieve lock info: %s
- lock id %q does not match existing lock
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/d35639c495dec685.
Report an issue: GitHub.