{"record":{"id":"6d0087245c8b219b","repo":"hashicorp/terraform","slug":"error-unmarshaling-lock-info-s","errorCode":null,"errorMessage":"error unmarshaling lock info: %s","messagePattern":"error unmarshaling lock info: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/consul/client.go","lineNumber":356,"sourceCode":"\t}, nil)\n\n\treturn err\n}\n\nfunc (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {\n\tpath := c.lockPath() + lockInfoSuffix\n\tpair, _, err := c.Client.KV().Get(path, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif pair == nil {\n\t\treturn nil, nil\n\t}\n\n\tli := &statemgr.LockInfo{}\n\terr = json.Unmarshal(pair.Value, li)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshaling lock info: %s\", err)\n\t}\n\n\treturn li, nil\n}\n\nfunc (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif !c.lockState {\n\t\treturn \"\", nil\n\t}\n\n\tc.info = info\n\n\t// These checks only are to ensure we strictly follow the specification.\n\t// Terraform shouldn't ever re-lock, so provide errors for the 2 possible\n\t// states if this is called.","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/consul/client.go#L338-L374","documentation":"RemoteClient.getLockInfo reads the KV pair at path+lockInfoSuffix and json.Unmarshal's its value into statemgr.LockInfo. If the bytes are not valid JSON for that schema, this fires. The lock info key is malformed.","triggerScenarios":"getLockInfo -> pair != nil -> json.Unmarshal(pair.Value, li) returns a non-nil error.","commonSituations":"A lock info key was written by an incompatible Terraform version with a different LockInfo schema; someone manually wrote a non-JSON payload at the .lock suffix key; Consul returned partial bytes from a corrupted snapshot; another tool collided on the same key namespace.","solutions":["Read the raw bytes: `consul kv get <path>.lock` and inspect the content.","If malformed and no Terraform run is active, delete it: `consul kv delete <path>.lock` after confirming.","Standardize the Terraform version across the team so LockInfo schemas agree.","Audit Consul KV usage to ensure no other writer is touching the lock suffix key."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before locking/unlocking, sanity-check the lock info key is valid JSON.\nfunc lockInfoValid(client *consulapi.Client, statePath string) error {\n    pair, _, err := client.KV().Get(strings.TrimRight(statePath, \"/\")+\".lock\", nil)\n    if err != nil || pair == nil {\n        return nil\n    }\n    var li statemgr.LockInfo\n    if err := json.Unmarshal(pair.Value, &li); err != nil {\n        return fmt.Errorf(\"lock info at %s.lock is corrupt: %w\", statePath, err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize the Terraform version across the team to keep LockInfo schemas aligned.","Never manually write to the .lock suffix key.","Periodically inspect the lock key only with consul kv get, never with writers.","After incidents, clean up malformed lock keys before re-running."],"tags":["consul","backend","state-locking","state-corruption"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}