{"record":{"id":"22020ea32c092c6f","repo":"hashicorp/terraform","slug":"lock-id-mismatch-v-v","errorCode":null,"errorMessage":"lock id mismatch, %v != %v","messagePattern":"lock id mismatch, (.+?) != (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/cos/client.go","lineNumber":126,"sourceCode":"\terr = c.putObject(c.lockFile, data)\n\tif err != nil {\n\t\treturn \"\", c.lockError(err)\n\t}\n\n\treturn check, nil\n}\n\n// Unlock unlock remote state file\nfunc (c *remoteClient) Unlock(check string) error {\n\tlog.Printf(\"[DEBUG] unlock remote state file %s\", c.lockFile)\n\n\tinfo, err := c.lockInfo()\n\tif err != nil {\n\t\treturn c.lockError(err)\n\t}\n\n\tif info.ID != check {\n\t\treturn c.lockError(fmt.Errorf(\"lock id mismatch, %v != %v\", info.ID, check))\n\t}\n\n\terr = c.deleteObject(c.lockFile)\n\tif err != nil {\n\t\treturn c.lockError(err)\n\t}\n\n\terr = c.cosUnlock(c.bucket, c.lockFile)\n\tif err != nil {\n\t\treturn c.lockError(err)\n\t}\n\n\treturn nil\n}\n\n// lockError returns statemgr.LockError\nfunc (c *remoteClient) lockError(err error) *statemgr.LockError {\n\tlog.Printf(\"[DEBUG] failed to lock or unlock %s: %v\", c.lockFile, err)","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/cos/client.go#L108-L144","documentation":"remoteClient.Unlock(check) reads the lock file (lockInfo() sets info.ID to the stored md5 checksum) and compares it to the supplied check. A mismatch means the caller is trying to release a lock whose ID does not match the current lock object — i.e., the lock being unlocked is not the one the caller holds.","triggerScenarios":"Unlock(check) -> info.ID != check; lockError wraps the mismatch.","commonSituations":"User runs `terraform force-unlock` with a stale or wrong ID; the lock was lost (session/lock expired) and re-acquired by another run with a different md5; multiple locks in flight and the wrong one was targeted.","solutions":["Obtain the current lock ID: read the lock object's X-Cos-Meta-Md5 / md5 from the bucket at c.lockFile (or from the error output of the locking operation).","Run `terraform force-unlock <correct-ID>` with that ID.","If no active run holds the lock, manually delete the lock object."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify the supplied lock ID matches the stored lock object before Unlock.\nfunc verifyLockID(c *remoteClient, check string) error {\n    info, err := c.lockInfo()\n    if err != nil {\n        return err\n    }\n    if info.ID != check {\n        return fmt.Errorf(\"lock id mismatch, %v != %v\", info.ID, check)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// On mismatch, re-read the stored lock ID and guide the user.\nif err := c.Unlock(providedID); err != nil {\n    if strings.Contains(err.Error(), \"lock id mismatch\") {\n        info, lerr := c.lockInfo()\n        if lerr == nil {\n            return fmt.Errorf(\"wrong lock id; current id=%s. Run terraform force-unlock %s\", info.ID, info.ID)\n        }\n    }\n    return err\n}","preventionTips":["Copy the lock ID verbatim from the error that reported the lock, not from memory.","Don't run force-unlock concurrently for the same workspace.","If the lock object may be stale, inspect the bucket before acting.","Capture lock IDs in CI logs so recovery is unambiguous."],"tags":["cos","tencent-cloud","state-locking","backend"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}