hashicorp/terraform · error
Error unlocking oci state. Lock ID: %s Error: %s You may h
Error message
Error unlocking oci state. Lock ID: %s Error: %s You may have to force-unlock this state in order to use it again.
What it means
Emitted by the inline lockUnlock closure (backend_state.go:78-83) using the errStateUnlock constant when stateMgr.Unlock fails inside the init-write flow. The lock was acquired but could not be released, so the workspace is left locked. The message deliberately includes the lock ID and tells the user to force-unlock.
Source
Thrown at internal/backend/remote-state/oci/backend_state.go:80
exists = true
break
}
}
// We need to create the object so it's listed by States.
if !exists {
// take a lock on this state while we write it
lockInfo := statemgr.NewLockInfo()
lockInfo.Operation = "init"
lockId, err := b.client.Lock(lockInfo)
if err != nil {
return nil, diags.Append(fmt.Errorf("failed to lock oci 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
// This is to ensure that no one beat us to writing a state between
// the `exists` check and taking the lock.
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)
}View on GitHub (pinned to d32a084675)
Solutions
- Copy the Lock ID from the message and run `terraform force-unlock <LOCK_ID>` after verifying no operation is active.
- Inspect the bucket for the lock object; if it is already gone, the unlock effectively succeeded and you can proceed.
- Stabilize IAM/network before retrying; an unlock that fails once will keep failing for the same reason until the underlying cause is fixed.
- If force-unlock itself fails, delete the lock object directly in Object Storage.
Example fix
# recovery from the printed message: # Error unlocking oci state. Lock ID: 2024-... # You may have to force-unlock this state in order to use it again. terraform force-unlock 2024-...
Defensive patterns
Strategy: fallback
Type guard
func isUnlockFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "Error unlocking oci state")
} Try / catch
// After the init-write flow, if unlock fails, surface the lock ID for force-unlock
if err := lockUnlock(nil); err != nil {
// The state is now locked; instruct the user to force-unlock
log.Printf("[WARN] state left locked: %v. Run `terraform force-unlock <ID>`", err)
return err
} Prevention
- Treat any unlock failure as requiring force-unlock — do not retry the same operation without resolving the lock.
- Stabilize IAM/network before retrying so the unlock does not fail again.
- Log lock IDs prominently so operators can recover quickly.
- Audit concurrent force-unlock activity that could delete the lock out from under a running init.
When it happens
Trigger: stateMgr.Unlock internally calls RemoteClient.Unlock; that fails if the lock file was concurrently deleted (etag mismatch / 404), if the lock ID no longer matches (314), if credentials/permissions changed mid-operation, or on a transient network error during the delete.
Common situations: A second user force-unlocked the lock between your Lock and Unlock; IAM permission was revoked mid-run; a network blip hit exactly the unlock call; manual deletion of the lock object during init.
Related errors
- failed to lock oci state: %s
- Failed to retrieve lock information from OCI Object Storage:
- failed to lock state in Consul: %s
- can't delete default state
- failed to get existing lock file: %w
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/ed1f1af77bcab29d.
Report an issue: GitHub.