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

  1. Skip 'default' in any bulk-delete loop: filter the name out before calling DeleteWorkspace.
  2. If you want to reset default state, delete its contents (terraform state push of an empty state) rather than the workspace itself.
  3. 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

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


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/c0e46ef4c8268fcf. Report an issue: GitHub.