{"record":{"id":"bf973df4d8b9f952","repo":"hashicorp/terraform","slug":"failed-to-delete-state-file-v-v","errorCode":null,"errorMessage":"Failed to delete state file %v: %v","messagePattern":"Failed to delete state file (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/gcs/client.go","lineNumber":88,"sourceCode":"\t\t}\n\t\tif _, err := stateFileWriter.Write(data); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn stateFileWriter.Close()\n\t}()\n\tif err != nil {\n\t\treturn diags.Append(fmt.Errorf(\"Failed to upload state to %v: %v\", c.stateFileURL(), err))\n\t}\n\n\treturn diags\n}\n\nfunc (c *remoteClient) Delete() tfdiags.Diagnostics {\n\tvar diags tfdiags.Diagnostics\n\n\tctx := context.TODO()\n\tif err := c.stateFile().Delete(ctx); err != nil {\n\t\treturn diags.Append(fmt.Errorf(\"Failed to delete state file %v: %v\", c.stateFileURL(), err))\n\t}\n\n\treturn diags\n}\n\n// Lock writes to a lock file, ensuring file creation. Returns the generation\n// number, which must be passed to Unlock().\nfunc (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {\n\tctx := context.TODO()\n\n\t// update the path we're using\n\t// we can't set the ID until the info is written\n\tinfo.Path = c.lockFileURL()\n\n\tinfoJson, err := json.Marshal(info)\n\tif err != nil {\n\t\treturn \"\", err\n\t}","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/gcs/client.go#L70-L106","documentation":"Thrown by the remote client Delete when c.stateFile().Delete(ctx) fails. Delete is used by DeleteWorkspace to remove a workspace's state object.","triggerScenarios":"stateFile().Delete returns an error — missing storage.objects.delete permission, object does not exist (though typically that is tolerated by the API), precondition failure, or transport error.","commonSituations":"Service account has objectAdmin minus delete; attempting to delete a workspace whose state was already removed; object held by a retention policy; transient failures.","solutions":["Grant roles/storage.objectAdmin which includes objects.delete.","Confirm the workspace still has a state object; idempotently tolerate 'not found'.","Check bucket retention policy if deletes are being rejected.","Retry transient errors."],"exampleFix":"// before — no delete permission\n// after\ngsutil iam ch serviceAccount:terraform@proj.iam.gserviceaccount.com:roles/storage.objectAdmin gs://tf-state","handlingStrategy":"validation","validationCode":"// Pre-flight: confirm objects.delete permission.\n// Minimal test: gsutil rm gs://bucket/.delprobe","typeGuard":null,"tryCatchPattern":"// Make delete idempotent for 'not found'.\nif err := f.Delete(ctx); err != nil && !errors.Is(err, storage.ErrObjectNotExist) {\n    return err\n}","preventionTips":["Grant roles/storage.objectAdmin (includes delete).","Make deletion automation tolerate 'already gone'.","Check bucket retention policy if deletes are rejected."],"tags":["gcs","backend","storage","iam","state-delete","permissions"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}