hashicorp/terraform · error
failed to lock OSS state
Error message
failed to lock OSS state: %s
What it means
Thrown during StateMgr initialization when a new workspace's state object must be created: the backend takes a Tablestore lock (client.Lock) before writing the initial empty state, and that lock acquisition failed. The %s is the underlying lock error.
Solutions
- Run 'terraform force-unlock <LOCK_ID>' using the lock ID reported by the conflicting run.
- Confirm the OTS table grants ots:PutRow, ots:GetRow, ots:DeleteRow to the credentials in use.
- Coordinate to avoid concurrent 'terraform init' against the same new workspace.
- Retry after confirming OTS endpoint health.
Defensive patterns
Strategy: try-catch
Try / catch
// On init of a new workspace, catch lock failure and surface the conflicting lock ID.
lockId, err := client.Lock(lockInfo)
if err != nil {
var le *statemgr.LockError
if errors.As(err, &le) && le.Info != nil {
return fmt.Errorf("state locked by %s (id %s); run 'terraform force-unlock %s'",
le.Info.Who, le.Info.ID, le.Info.ID)
}
return err
} Prevention
- Serialize 'terraform init' across teammates (one initializer per workspace).
- Always force-unlock after a crashed run before re-initializing.
- Confirm OTS PutRow permission during provisioning.
When it happens
Trigger: client.Lock returns an error — typically the OTS PutRow for the lock record collided with an existing lock row (RowExistenceExpectation_EXPECT_NOT_FOUND failed), the OTS endpoint was unreachable, or credentials lacked PutRow permission.
Common situations: A previous terraform run crashed holding a lock; another user/process is concurrently initializing the same workspace; OTS table permissions missing; transient OTS unavailability.
Related errors
- Error unlocking Alibaba Cloud OSS state file: Lock ID
- getting lock info got an error: %#v
- invoking PutRow got an error: %#v
- failed to retrieve lock info
- error describing table store
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/8bb340a8851a9f33.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/oss/backend_state.go:151
}
log.Printf("[DEBUG] Current workspace name: %s. All workspaces:%#v", name, existing)
exists := false
for _, s := range existing {
if s == name {
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 := client.Lock(lockInfo)
if err != nil {
return nil, diags.Append(fmt.Errorf("failed to lock OSS 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(strings.TrimSpace(stateUnlockError), lockId, err)
}
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 {View on GitHub (pinned to d32a084675)