hashicorp/terraform · warning
cowardly refusing to delete the %q state
Error message
cowardly refusing to delete the %q state
What it means
DeleteWorkspace refuses to delete the workspace literally named 'default' (backend.DefaultStateName). The default workspace is special in Terraform and must always exist, so the GCS backend hard-blocks the operation regardless of the force flag. The %q is always 'default'.
Source
Thrown at internal/backend/remote-state/gcs/backend_state.go:69
if !strings.HasSuffix(name, stateFileSuffix) {
continue
}
st := strings.TrimSuffix(name, stateFileSuffix)
if st != backend.DefaultStateName {
states = append(states, st)
}
}
sort.Strings(states[1:])
return states, diags
}
// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
func (b *Backend) DeleteWorkspace(name string, _ bool) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if name == backend.DefaultStateName {
return diags.Append(fmt.Errorf("cowardly refusing to delete the %q state", name))
}
c, err := b.client(name)
if err != nil {
return diags.Append(err)
}
return diags.Append(c.Delete())
}
// client returns a remoteClient for the named state.
func (b *Backend) client(name string) (*remoteClient, error) {
if name == "" {
return nil, fmt.Errorf("%q is not a valid state name", name)
}
return &remoteClient{
storageClient: b.storageClient,View on GitHub (pinned to c9def3e214)
Solutions
- Skip 'default' in any bulk-delete loop: filter the name out before calling DeleteWorkspace.
- If you want to reset default state, delete its contents (terraform state push of an empty state) rather than the workspace itself.
- Update scripts: for w in $(terraform workspace list | grep -v default); do terraform workspace delete "$w"; done.
Example fix
// before
for name := range workspaces {
backend.DeleteWorkspace(name, true) // fails on "default"
}
// after
for name := range workspaces {
if name == backend.DefaultStateName { continue }
backend.DeleteWorkspace(name, true)
} Defensive patterns
Strategy: validation
Validate before calling
for _, name := range workspaces {
if name == backend.DefaultStateName { continue } // never delete default
_ = backend.DeleteWorkspace(name, true)
} Type guard
func isDefaultState(name string) bool { return name == "default" } Prevention
- Always exclude 'default' from bulk-delete loops.
- Document the reservation in team runbooks.
- Use terraform workspace list output filtering rather than ad-hoc iteration.
When it happens
Trigger: Calling 'terraform workspace delete default' or invoking DeleteWorkspace("default", _) programmatically against the GCS backend.
Common situations: Scripted cleanup that loops over all workspaces and tries to delete each including default; CI teardown that nukes everything; misunderstanding that default is reserved.
Related errors
- %q is not a valid state name
- impersonate_service_account_delegates elements must not be n
- Error loading encryption key: %s
- Error decoding encryption key: %s
- querying Cloud Storage failed: %v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/c0e46ef4c8268fcf.
Report an issue: GitHub.