hashicorp/terraform · error
lock id mismatch, !=
Error message
lock id mismatch, %v != %v
What it means
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.
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.
Defensive patterns
Strategy: validation
Validate before calling
// Verify the supplied lock ID matches the stored lock object before Unlock.
func verifyLockID(c *remoteClient, check string) error {
info, err := c.lockInfo()
if err != nil {
return err
}
if info.ID != check {
return fmt.Errorf("lock id mismatch, %v != %v", info.ID, check)
}
return nil
} Try / catch
// On mismatch, re-read the stored lock ID and guide the user.
if err := c.Unlock(providedID); err != nil {
if strings.Contains(err.Error(), "lock id mismatch") {
info, lerr := c.lockInfo()
if lerr == nil {
return fmt.Errorf("wrong lock id; current id=%s. Run terraform force-unlock %s", info.ID, info.ID)
}
}
return err
} Prevention
- 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.
When it happens
Trigger: Unlock(check) -> info.ID != check; lockError wraps the mismatch.
Common situations: 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.
Related errors
- Failed to lock cos state
- lock file exists
- Unlocking the state file on TencentCloud cos backend…
- acl value invalid, expected
- default state is not allowed to be deleted
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/22020ea32c092c6f.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/cos/client.go:126
err = c.putObject(c.lockFile, data)
if err != nil {
return "", c.lockError(err)
}
return check, nil
}
// Unlock unlock remote state file
func (c *remoteClient) Unlock(check string) error {
log.Printf("[DEBUG] unlock remote state file %s", c.lockFile)
info, err := c.lockInfo()
if err != nil {
return c.lockError(err)
}
if info.ID != check {
return c.lockError(fmt.Errorf("lock id mismatch, %v != %v", info.ID, check))
}
err = c.deleteObject(c.lockFile)
if err != nil {
return c.lockError(err)
}
err = c.cosUnlock(c.bucket, c.lockFile)
if err != nil {
return c.lockError(err)
}
return nil
}
// lockError returns statemgr.LockError
func (c *remoteClient) lockError(err error) *statemgr.LockError {
log.Printf("[DEBUG] failed to lock or unlock %s: %v", c.lockFile, err)View on GitHub (pinned to d32a084675)