{"record":{"id":"b3b82e05845b4b16","repo":"hashicorp/terraform","slug":"could-not-write-lock-info-for-q-s","errorCode":null,"errorMessage":"could not write lock info for %q: %s","messagePattern":"could not write lock info for %q: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/clistate/local_state.go","lineNumber":312,"sourceCode":"\t}\n\n\tinfo := statemgr.LockInfo{}\n\terr = json.Unmarshal(infoData, &info)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"state file %q locked, but could not unmarshal lock info: %s\", s.Path, err)\n\t}\n\treturn &info, nil\n}\n\n// write a new lock info file\nfunc (s *LocalState) writeLockInfo(info *statemgr.LockInfo) error {\n\tpath := s.lockInfoPath()\n\tinfo.Path = s.Path\n\tinfo.Created = time.Now().UTC()\n\n\terr := ioutil.WriteFile(path, info.Marshal(), 0600)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not write lock info for %q: %s\", s.Path, err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":294,"sourceCodeEnd":316,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/clistate/local_state.go#L294-L316","documentation":"Returned by LocalState.writeLockInfo (local_state.go:305) when ioutil.WriteFile fails to create/overwrite the lock info metadata file (.terraform.tfstate.lock.info) with mode 0600. writeLockInfo is the final step of Lock after the OS-level file lock (s.lock) succeeded; it persists the LockInfo record so other processes can identify the lock holder. Failure here means the lock is held but not documented.","triggerScenarios":"ioutil.WriteFile returns an error: the state directory is read-only or missing, permission denied on the directory, disk full, path too long, or the process lost write permission between acquiring the file lock and writing the metadata.","commonSituations":"The state directory is on a read-only mount; another user owns the directory; the directory was deleted between locking and writing info; disk filled up; running in a sandbox that allows file locking but not file creation.","solutions":["Check write permission on the directory containing the state file: `ls -ld $(dirname <statefile>)` and `touch <dir>/.write-test`.","Ensure the state directory exists and is writable by the Terraform process: `mkdir -p .terraform && chmod u+w .terraform`.","Free disk space if the volume is full.","If the directory was deleted mid-run, recreate it and re-run; call `terraform force-unlock` to clean up any half-acquired lock before retrying."],"exampleFix":"# before\n$ terraform plan\ncould not write lock info for \"terraform.tfstate\": open .terraform.tfstate.lock.info: permission denied\n\n# after\n$ chmod u+w .\n$ terraform force-unlock <id>   # clear any partial lock\n$ terraform plan","handlingStrategy":"validation","validationCode":"// Ensure the state directory is writable before locking\nstateDir := filepath.Dir(s.Path)\nif err := os.MkdirAll(stateDir, 0755); err != nil {\n    return fmt.Errorf(\"state dir unusable: %w\", err)\n}\nprobe := filepath.Join(stateDir, \".write-probe\")\nif err := ioutil.WriteFile(probe, []byte(\"\"), 0600); err != nil {\n    return fmt.Errorf(\"state dir not writable: %w\", err)\n}\nos.Remove(probe)","typeGuard":null,"tryCatchPattern":"// If writeLockInfo fails after acquiring the OS lock, attempt to release the OS lock to avoid a held-but-undocumented lock.\nif err := s.writeLockInfo(info); err != nil {\n    if uerr := s.unlock(); uerr != nil {\n        log.Printf(\"warning: failed to write lock info (%v) and failed to roll back OS lock (%v)\", err, uerr)\n    }\n    s.lockID = \"\"\n    return fmt.Errorf(\"could not persist lock info: %w\", err)\n}","preventionTips":["Pre-flight check write permission on the state directory.","Keep the state directory on local, writable storage.","In CI, create the state directory explicitly before running Terraform.","Document the lock info file path so operators can inspect it."],"tags":["state","locking","filesystem","permissions","local-backend"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}