hashicorp/terraform · error · LockError
writing failed
Error message
writing %q failed: %v
What it means
Thrown by the remote client Lock when writing the lock file fails. Lock uses a precondition (storage.Conditions{DoesNotExist: true}) so the write is rejected if a lock file already exists; any other write/close error is also wrapped here via c.lockError.
Solutions
- If another run legitimately holds the lock, wait for it to finish or run `terraform force-unlock <id>`.
- Inspect the returned LockError.Info for the existing lock's owner and ID.
- Grant objects.create permission on the bucket (lock files live alongside state).
- Add a pre-run check that no stale lock exists, and clean it up deliberately.
Example fix
// recovery $ terraform force-unlock <existing-lock-id> # then retry terraform apply
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: detect an existing lock file before attempting to acquire. // gsutil stat gs://bucket/<prefix>default.tflock && echo "LOCK HELD"
Type guard
func isPreconditionFailed(err error) bool {
var ge *googleapi.Error
return errors.As(err, &ge) && ge.Code == 412
} Try / catch
// On 412, surface existing lock info and instruct force-unlock.
if err := c.Lock(info); err != nil {
if isPreconditionFailed(err) {
return fmt.Errorf("state already locked; run terraform force-unlock")
}
return err
} Prevention
- Serialize CI jobs that share state via a higher-level lock or queue.
- Clean up stale locks deliberately with force-unlock, never by ignoring errors.
- Ensure the account has objects.create on the lock path.
When it happens
Trigger: lockFile.If(DoesNotExist:true).NewWriter write or close fails — most commonly a 412 Precondition Failed because another process holds the lock, but also transport errors or missing objects.create permission on the lock path.
Common situations: Two CI jobs racing to acquire the lock; a previous terraform run crashed leaving a stale lock; service account cannot create the lock object.
Related errors
- Failed to delete state file
- Failed to open state file at
- Failed to upload state to
- Lock ID should be numerical value, got
- querying Cloud Storage failed
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/95fde91f955a379b.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/gcs/client.go:118
// we can't set the ID until the info is written
info.Path = c.lockFileURL()
infoJson, err := json.Marshal(info)
if err != nil {
return "", err
}
lockFile := c.lockFile()
w := lockFile.If(storage.Conditions{DoesNotExist: true}).NewWriter(ctx)
err = func() error {
if _, err := w.Write(infoJson); err != nil {
return err
}
return w.Close()
}()
if err != nil {
return "", c.lockError(fmt.Errorf("writing %q failed: %v", c.lockFileURL(), err))
}
info.ID = strconv.FormatInt(w.Attrs().Generation, 10)
return info.ID, nil
}
func (c *remoteClient) Unlock(id string) error {
ctx := context.TODO()
gen, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return fmt.Errorf("Lock ID should be numerical value, got '%s'", id)
}
if err := c.lockFile().If(storage.Conditions{GenerationMatch: gen}).Delete(ctx); err != nil {
return c.lockError(err)
}View on GitHub (pinned to d32a084675)