{"record":{"id":"8bb340a8851a9f33","repo":"hashicorp/terraform","slug":"failed-to-lock-oss-state-s","errorCode":null,"errorMessage":"failed to lock OSS state: %s","messagePattern":"failed to lock OSS state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oss/backend_state.go","lineNumber":151,"sourceCode":"\t}\n\n\tlog.Printf(\"[DEBUG] Current workspace name: %s. All workspaces:%#v\", name, existing)\n\n\texists := false\n\tfor _, s := range existing {\n\t\tif s == name {\n\t\t\texists = true\n\t\t\tbreak\n\t\t}\n\t}\n\t// We need to create the object so it's listed by States.\n\tif !exists {\n\t\t// take a lock on this state while we write it\n\t\tlockInfo := statemgr.NewLockInfo()\n\t\tlockInfo.Operation = \"init\"\n\t\tlockId, err := client.Lock(lockInfo)\n\t\tif err != nil {\n\t\t\treturn nil, diags.Append(fmt.Errorf(\"failed to lock OSS state: %s\", err))\n\t\t}\n\n\t\t// Local helper function so we can call it multiple places\n\t\tlockUnlock := func(e error) error {\n\t\t\tif err := stateMgr.Unlock(lockId); err != nil {\n\t\t\t\treturn fmt.Errorf(strings.TrimSpace(stateUnlockError), lockId, err)\n\t\t\t}\n\t\t\treturn e\n\t\t}\n\n\t\t// Grab the value\n\t\tif err := stateMgr.RefreshState(); err != nil {\n\t\t\terr = lockUnlock(err)\n\t\t\treturn nil, diags.Append(err)\n\t\t}\n\n\t\t// If we have no state, we have to create an empty state\n\t\tif v := stateMgr.State(); v == nil {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/oss/backend_state.go#L133-L169","documentation":"In StateMgr() (backend_state.go:149-151), when initializing a brand-new workspace state, client.Lock(lockInfo) failed. Lock() (client.go:153) attempts a conditional PutRow into TableStore; on failure it returns a statemgr.LockError whose message is wrapped here. This means another process holds the lock or the OTS write was rejected.","triggerScenarios":"StateMgr creating a not-yet-existing workspace takes an init lock; the OTS PutRow with RowExistenceExpectation_EXPECT_NOT_EXIST fails because a lock row already exists (concurrent init, stale lock from a crashed run) or because of an OTS service/permission error.","commonSituations":"Two CI runners initializing the same workspace simultaneously; a previous terraform process was killed leaving a stale lock row; OTS throttling; RAM policy lacks tablestore:PutRow.","solutions":["Run terraform force-unlock <LOCK_ID> using the lock ID from the error to clear the stale row.","Serialize workspace initialization (one runner/branch at a time) to avoid concurrent init races.","Confirm the credentials have tablestore:PutRow and tablestore:GetRow on the OTS table.","If OTS is throttling, retry after a brief backoff or raise the instance throughput quota."],"exampleFix":"# before: stale lock blocks init\nterraform init\n\n# after\nterraform force-unlock a1b2c3d4-...\nterraform init","handlingStrategy":"try-catch","validationCode":"// Before init, check whether a lock row already exists for this state path.\nfunc lockHeld(c *tablestore.TableStoreClient, table, lockPath string) bool {\n    _, err := c.GetRow(&tablestore.GetRowRequest{SingleRowQueryCriteria: &tablestore.SingleRowQueryCriteria{\n        TableName: table,\n        PrimaryKey: &tablestore.PrimaryKey{PrimaryKeys: []*tablestore.PrimaryKeyColumn{\n            {ColumnName: \"LockID\", Value: lockPath},\n        }},\n        MaxVersion: 1,\n    }})\n    return err == nil\n}","typeGuard":null,"tryCatchPattern":"// On init, if the error indicates a held lock, prompt for force-unlock.\nif err != nil && strings.Contains(err.Error(), \"failed to lock OSS state\") {\n    fmt.Println(\"state is locked; run: terraform force-unlock <ID>\")\n    return err\n}","preventionTips":["Serialize workspace initialization across CI runners.","Always exit CI with terraform force-unlock on failure, or use a finally-block.","Confirm the OTS table and PutRow permission before relying on locking."],"tags":["alibaba-cloud","tablestore","ots","remote-state","locking","go"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}