hashicorp/terraform · error
cowardly refusing to delete the
Error message
cowardly refusing to delete the %q state
What it means
Returned by DeleteWorkspace when the requested workspace name equals backend.DefaultStateName ("default"). The default state is the primary state and is protected from deletion regardless of the force flag.
Solutions
- Skip the default workspace in any deletion loop: filter out name == "default".
- Do not attempt `terraform workspace delete default`; the default workspace is non-deletable.
- If you truly need to clear it, manually delete state objects in GCS rather than using DeleteWorkspace.
Example fix
// before for ws in $(terraform workspace list); do terraform workspace delete "$ws"; done // after for ws in $(terraform workspace list); do [ "$ws" = "default" ] && continue; terraform workspace delete "$ws"; done
Defensive patterns
Strategy: validation
Validate before calling
// Never call DeleteWorkspace for the default state.
const defaultName = "default"
if name == defaultName {
return nil // or log and skip
}
return backend.DeleteWorkspace(name, force) Type guard
func isDefaultWorkspace(name string) bool { return name == backend.DefaultStateName } Prevention
- Always filter 'default' out of workspace-deletion loops.
- Treat the default workspace as non-deletable in automation scripts.
When it happens
Trigger: DeleteWorkspace is invoked with name == backend.DefaultStateName ("default"). The force argument is ignored — the guard is unconditional.
Common situations: An automation script iterates all workspaces and tries to delete each, including default; a user runs `terraform workspace delete default`; tooling that wraps `terraform workspace list` and deletes every entry.
Related errors
- is not a valid state name
- querying Cloud Storage failed
- Error decoding encryption key
- Error inspecting states in the
- Error inspecting states in the
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/c0e46ef4c8268fcf.
Report an issue: GitHub.
Appendix: 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 d32a084675)