hashicorp/terraform · error
Failed to delete state file %v: %v
Error message
Failed to delete state file %v: %v
What it means
remoteClient.Delete() calls stateFile().Delete(ctx) to remove the .tfstate object; any error (object not present is still an error here, unlike Get) is wrapped with the gs:// URL. Triggered by DeleteWorkspace after the name passes validation, and by explicit state-file deletion.
Source
Thrown at internal/backend/remote-state/gcs/client.go:88
}
if _, err := stateFileWriter.Write(data); err != nil {
return err
}
return stateFileWriter.Close()
}()
if err != nil {
return diags.Append(fmt.Errorf("Failed to upload state to %v: %v", c.stateFileURL(), err))
}
return diags
}
func (c *remoteClient) Delete() tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
ctx := context.TODO()
if err := c.stateFile().Delete(ctx); err != nil {
return diags.Append(fmt.Errorf("Failed to delete state file %v: %v", c.stateFileURL(), err))
}
return diags
}
// Lock writes to a lock file, ensuring file creation. Returns the generation
// number, which must be passed to Unlock().
func (c *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
ctx := context.TODO()
// update the path we're using
// 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
}View on GitHub (pinned to c9def3e214)
Solutions
- If %v is 'notFound', the workspace is already gone — treat as success in automation (no-op).
- Grant SA 'roles/storage.objectAdmin' (includes delete) or a custom role with storage.objects.delete.
- Remove bucket retention policy / object holds blocking the delete, or wait for retention to elapse.
- Retry; transient 5xx during delete is possible.
Example fix
// before: SA lacks delete roles/storage.objectCreator only // after gsutil iam ch serviceAccount:tf@proj.iam.gserviceaccount.com:roles/storage.objectAdmin gs://bucket terraform workspace delete <ws>
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check object existence to make delete idempotent
ctx := context.Background()
_, err := client.Bucket(bucket).Object(statePath).Attrs(ctx)
if err == storage.ErrObjectNotExist { return nil } Type guard
import "strings"
func isAlreadyGone(err error) bool { return strings.Contains(err.Error(), "notFound") || err == storage.ErrObjectNotExist } Try / catch
if diags := client.Delete(); diags.HasErrors() {
if isAlreadyGone(diags.Err()) { return nil } // idempotent
return diags
} Prevention
- Make workspace-deletion automation idempotent: treat 'notFound' as success.
- Grant SA storage.objects.delete.
- Avoid retention policies on state buckets or account for them in teardown.
When it happens
Trigger: 'terraform workspace delete <ws>' removing its state object; the object was already deleted by another process (returns notFound); SA lacks storage.objects.delete; bucket has a retention policy holding the object.
Common situations: Idempotent workspace deletion racing with another teardown; SA has objectAdmin for create/get but not delete; retention policy / object holds blocking deletion.
Related errors
- Failed to open state file at %v: %v
- querying Cloud Storage failed: %v
- Failed to read state file from %v: %v
- Failed to read state file attrs from %v: %v
- Failed to upload state to %v: %v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/bf973df4d8b9f952.
Report an issue: GitHub.