hashicorp/terraform · error
Unlocking the state file on TencentCloud cos backend failed
Error message
Unlocking the state file on TencentCloud cos backend failed: Error message: %v Lock ID (gen): %s You may have to force-unlock this state in order to use it again. The TencentCloud backend acquires a lock during initialization to ensure the initial state file is created.
What it means
Mirror of 181 for COS. After taking the init lock and failing on RefreshState/WriteState/PersistState, the lockUnlock helper calls stateMgr.Unlock(lockId); if that unlock itself fails (formatted by unlockErrMsg), this error is raised and the user is told to force-unlock.
Source
Thrown at internal/backend/remote-state/cos/backend_state.go:121
break
}
}
if !exists {
log.Printf("[DEBUG] workspace %v not exists", name)
// take a lock on this state while we write it
lockInfo := statemgr.NewLockInfo()
lockInfo.Operation = "init"
lockId, err := c.Lock(lockInfo)
if err != nil {
return nil, diags.Append(fmt.Errorf("Failed to lock cos state: %s", err))
}
// Local helper function so we can call it multiple places
lockUnlock := func(e error) error {
if err := stateMgr.Unlock(lockId); err != nil {
return fmt.Errorf(unlockErrMsg, err, lockId)
}
return e
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, diags.Append(err)
}
// If we have no state, we have to create an empty state
if v := stateMgr.State(); v == nil {
if err := stateMgr.WriteState(states.NewState()); err != nil {
err = lockUnlock(err)
return nil, diags.Append(err)
}
if err := stateMgr.PersistState(nil); err != nil {
err = lockUnlock(err)View on GitHub (pinned to d32a084675)
Solutions
- Capture the Lock ID (gen) printed in the message and run `terraform force-unlock <LOCK_ID>`.
- Inspect the lock object at the lock file path in the bucket; remove it manually if stale.
- Verify COS service status and credentials before retrying.
Defensive patterns
Strategy: try-catch
Try / catch
// If init failed with a dangling lock, attempt recovery once.
sm, diags := backend.StateMgr(name)
if diags.HasErrors() {
msg := diags.Err().Error()
if strings.Contains(msg, "force-unlock") {
if id := extractLockID(msg); id != "" {
log.Printf("init left dangling lock %s; attempting force-unlock", id)
if _, uerr := sm.Unlock(id); uerr != nil {
return fmt.Errorf("manual recovery required: %w", uerr)
}
}
}
return diags.Err()
} Prevention
- Keep COS reachable from the Terraform host; check COS status before runs.
- Don't revoke COS credentials mid-operation.
- Have a force-unlock runbook and capture lock IDs in CI logs.
- Audit the bucket for orphaned lock files periodically.
When it happens
Trigger: In StateMgr init, one of RefreshState/WriteState/PersistState errors; lockUnlock's stateMgr.Unlock(lockId) returns non-nil; the helper returns fmt.Errorf(unlockErrMsg, err, lockId).
Common situations: COS connectivity lost mid-init; lock object deleted externally before unlock; COS 5xx during DeleteObject on the lock file; lock id mismatch because the lock was already released or re-acquired.
Related errors
- Failed to lock cos state: %s
- lock file %s exists
- lock id mismatch, %v != %v
- Error unlocking Consul state. Lock ID: %s Error: %s You ma
- prefix must not start with '/' or './'
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/f8d18730dc8200ed.
Report an issue: GitHub.