{"record":{"id":"e05ee4e97ff44011","repo":"hashicorp/terraform","slug":"failed-to-lock-azure-state-s","errorCode":null,"errorMessage":"failed to lock azure state: %s","messagePattern":"failed to lock azure state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/azure/backend_state.go","lineNumber":119,"sourceCode":"\t\taccountName:        b.accountName,\n\t\tsnapshot:           b.snapshot,\n\t}\n\n\tstateMgr := &remote.State{Client: client}\n\n\t// Grab the value\n\tif err := stateMgr.RefreshState(); err != nil {\n\t\treturn nil, diags.Append(err)\n\t}\n\t//if this isn't the default state name, we need to create the object so\n\t//it's listed by States.\n\tif v := stateMgr.State(); v == nil {\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 azure state: %s\", err))\n\t\t}\n\n\t\t// Local helper function so we can call it multiple places\n\t\tlockUnlock := func(parent error) error {\n\t\t\tif err := stateMgr.Unlock(lockId); err != nil {\n\t\t\t\treturn fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)\n\t\t\t}\n\t\t\treturn parent\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\t\t//if this isn't the default state name, we need to create the object so\n\t\t//it's listed by States.\n\t\tif v := stateMgr.State(); v == nil {","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/azure/backend_state.go#L101-L137","documentation":"Thrown by StateMgr when a workspace state object does not yet exist and the backend tries to acquire a lease-based lock to initialize it, but client.Lock returns an error. Lock fails when another client already holds the lease, when a stale lease from a crashed run remains, or when the lock-info metadata write fails.","triggerScenarios":"(a) Another terraform process already acquired the lease on the same state blob. (b) A prior run crashed without releasing (stale lease). (c) writeLockInfo failed (SetMetaData network/RBAC error). (d) AcquireLease itself failed (throttling).","commonSituations":"Concurrent `terraform apply` in two terminals against the same workspace; CI overlap; crashed run left a lease; long-held lock from interrupted operation.","solutions":["Run `terraform force-unlock <lock-id>` using the ID printed in the LockError info.","If the other run is legitimate, wait for it to finish then retry.","Inspect the lease via Azure portal or `az storage blob lease list` / `show`.","If the lock info metadata is corrupt, break the lease manually via `az storage blob lease break`."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight: check whether the state blob is already leased before attempting to lock.\nfunc isStateBlobLeased(ctx context.Context, acct, container, blob string) (bool, error) {\n    cmd := exec.CommandContext(ctx, \"az\", \"storage\", \"blob\", \"show\",\n        \"--account-name\", acct, \"-c\", container, \"-n\", blob, \"--query\", \"properties.lease.status\", \"-o\", \"tsv\")\n    out, err := cmd.Output()\n    if err != nil { return false, err }\n    return strings.TrimSpace(string(out)) == \"locked\", nil\n}","typeGuard":null,"tryCatchPattern":"// On a lock failure, parse the LockError and offer the lock id for force-unlock.\nstateMgr, diags := backend.StateMgr(name)\nif diags.HasErrors() {\n    var le *statemgr.LockError\n    if errors.As(diags.Err(), &le) && le.Info != nil {\n        log.Printf(\"state is locked by %s; run: terraform force-unlock %s\", le.Info.Operation, le.Info.ID)\n    }\n}","preventionTips":["Coordinate team / CI access to a shared workspace to avoid overlapping runs.","Always run `terraform force-unlock <id>` only after confirming the holder is dead.","Monitor stale leases via a periodic `az storage blob lease list` script."],"tags":["azure","state-locking","lease","concurrency","workspace"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}