{"record":{"id":"bbec0dd77fbeb0b4","repo":"hashicorp/terraform","slug":"lock-id-s-does-not-match-the-existing-lock-id","errorCode":null,"errorMessage":"lock ID '%s' does not match the existing lock ID '%s'","messagePattern":"lock ID '(.+?)' does not match the existing lock ID '(.+?)'","errorType":"exception","errorClass":"statemgr.LockError","httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oci/client.go","lineNumber":337,"sourceCode":"\tif err := json.Unmarshal(lockByteData, lockInfo); err != nil {\n\t\treturn lockInfo, \"\", fmt.Errorf(\"failed to unmarshal JSON data into LockInfo struct: %w\", err)\n\t}\n\treturn lockInfo, *getResponse.ETag, nil\n}\nfunc (c *RemoteClient) Unlock(id string) error {\n\tctx := context.TODO()\n\tlogger := logWithOperation(\"unlock-state-file\").Named(c.lockFilePath)\n\tlogger.Info(\"unlocking remote state\")\n\tlockInfo, etag, err := c.getLockInfo(ctx)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to retrieve lock information from OCI Object Storage: %w\", err)\n\t}\n\t// Verify that the provided lock ID matches the lock ID of the retrieved lock file.\n\tif lockInfo.ID != id {\n\t\treturn &statemgr.LockError{\n\t\t\tInfo: lockInfo,\n\t\t\tErr:  fmt.Errorf(\"lock ID '%s' does not match the existing lock ID '%s'\", id, lockInfo.ID),\n\t\t}\n\t}\n\n\tdeleteRequest := objectstorage.DeleteObjectRequest{\n\t\tNamespaceName: common.String(c.namespace),\n\t\tObjectName:    common.String(c.lockFilePath),\n\t\tBucketName:    common.String(c.bucketName),\n\t\tIfMatch:       common.String(etag),\n\t\tRequestMetadata: common.RequestMetadata{\n\t\t\tRetryPolicy: getDefaultRetryPolicy(),\n\t\t},\n\t}\n\tdeleteResponse, err := c.objectStorageClient.DeleteObject(ctx, deleteRequest)\n\tif err != nil {\n\t\treturn &statemgr.LockError{\n\t\t\tInfo: lockInfo,\n\t\t\tErr:  err,\n\t\t}","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/oci/client.go#L319-L355","documentation":"Raised in Unlock when the lock ID supplied by the caller does not equal lockInfo.ID read from the existing lock file. This is a deliberate guard preventing one process from unlocking state that another process holds. It is returned as a statemgr.LockError carrying the current LockInfo so the caller can report who actually holds the lock.","triggerScenarios":"Unlock(id) is called with an id that differs from lockInfo.ID at client.go:334. Happens when force-unlock is attempted with a stale/wrong ID, or when the lock was re-acquired by a different run after the caller's ID became stale.","commonSituations":"User runs 'terraform force-unlock <old-id>' after the lock was already released and re-acquired with a new ID; copy-pasting the wrong ID; two operators racing to unlock.","solutions":["Read the current lock file (oci os object get <lockfile>) to obtain the real lockInfo.ID and use that ID for force-unlock.","Confirm via the LockInfo Who/Operation/Created fields that it is genuinely safe to unlock (no active run holds it).","Only after confirming, delete the lock object directly if Terraform's unlock keeps refusing the ID.","Avoid force-unlock when an apply is in progress; coordinate with the listed lock owner first."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before Unlock, read the current lock file and obtain the real ID:\n//   oci os object get --namespace <ns> --bucket-name <b> --name <lockfile> --file -\n// Pass the JSON's \"ID\" to force-unlock, not a stale/copy-pasted id.","typeGuard":"// The lib returns a *statemgr.LockError carrying the real holder; use it:\nvar le *statemgr.LockError\nif errors.As(err, &le) && le.Info != nil {\n    // le.Info.ID is who really holds the lock; le.Info.Who/Operation/Path for context\n}","tryCatchPattern":"if lockInfo.ID != id {\n    return &statemgr.LockError{Info: lockInfo, Err: fmt.Errorf(\"lock ID '%s' does not match the existing lock ID '%s'\", id, lockInfo.ID)}\n}","preventionTips":["Always force-unlock with the ID reported by Terraform, not a remembered one.","Verify the real holder via LockInfo.Who/Operation before unlocking.","Coordinate unlock with teammates to avoid races."],"tags":["oci","object-storage","locking","lock-id","force-unlock","terraform-state"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}