{"record":{"id":"35d4fd66e3640cb7","repo":"hashicorp/terraform","slug":"failed-to-retrieve-lock-info-s-35d4fd","errorCode":null,"errorMessage":"failed to retrieve lock info: %s","messagePattern":"failed to retrieve lock info: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oss/client.go","lineNumber":373,"sourceCode":"\t\tinfoData = v[0].Value.(string)\n\t}\n\tlockInfo := &statemgr.LockInfo{}\n\terr = json.Unmarshal([]byte(infoData), lockInfo)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn lockInfo, nil\n}\nfunc (c *RemoteClient) Unlock(id string) error {\n\tif c.otsTable == \"\" {\n\t\treturn nil\n\t}\n\n\tlockErr := &statemgr.LockError{}\n\n\tlockInfo, err := c.getLockInfo()\n\tif err != nil {\n\t\tlockErr.Err = fmt.Errorf(\"failed to retrieve lock info: %s\", err)\n\t\treturn lockErr\n\t}\n\tlockErr.Info = lockInfo\n\n\tif lockInfo.ID != id {\n\t\tlockErr.Err = fmt.Errorf(\"lock id %q does not match existing lock\", id)\n\t\treturn lockErr\n\t}\n\tparams := &tablestore.DeleteRowRequest{\n\t\tDeleteRowChange: &tablestore.DeleteRowChange{\n\t\t\tTableName: c.otsTable,\n\t\t\tPrimaryKey: &tablestore.PrimaryKey{\n\t\t\t\tPrimaryKeys: []*tablestore.PrimaryKeyColumn{\n\t\t\t\t\t{\n\t\t\t\t\t\tColumnName: pkName,\n\t\t\t\t\t\tValue:      c.lockPath(),\n\t\t\t\t\t},\n\t\t\t\t},","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/oss/client.go#L355-L391","documentation":"Thrown by RemoteClient.Unlock at the start of unlock: getLockInfo() failed before any deletion is attempted. The unlock cannot proceed because it cannot verify which lock is held; the error is wrapped in a statemgr.LockError whose Info is left nil.","triggerScenarios":"Calling Unlock(id) and getLockInfo() errors — OTS GetRow on the lock path failed: table missing, credentials lack ots:GetRow, endpoint unreachable, or the lock row was already removed out-of-band.","commonSituations":"A stale lock was manually deleted before terraform tried to unlock; OTS permissions changed mid-run; OTS regional issue; lock row primary key shape mismatch.","solutions":["Verify the OTS table exists and the lock row is present.","Grant ots:GetRow and ots:DeleteRow on the table.","If the lock row was already removed, the unlock error is benign — confirm no lock row remains and proceed.","Retry the terraform command once OTS is reachable."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// In Unlock, if getLockInfo fails, treat already-absent row as success; otherwise surface LockError.\ninfo, err := c.getLockInfo()\nif err != nil {\n    if isRowNotExist(err) { return nil } // lock already gone — nothing to unlock\n    return &statemgr.LockError{Err: fmt.Errorf(\"failed to retrieve lock info: %s\", err)}\n}","preventionTips":["Grant ots:GetRow and ots:DeleteRow on the lock table for the lifetime of the run.","Avoid manually deleting lock rows out-of-band; use 'terraform force-unlock'.","Confirm OTS table existence before running operations that unlock."],"tags":["alibaba-cloud","tablestore","ots","state-lock","unlock","remote-state"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}