hashicorp/terraform · error

can't delete default state

Error message

can't delete default state

What it means

Thrown by Backend.DeleteWorkspace in the PostgreSQL state backend when the requested workspace name equals backend.DefaultStateName ("default") or the empty string. The default workspace holds the canonical state and must never be removed; deleting it would orphan all resources in the DB. This is a hard guard at the top of DeleteWorkspace before any SQL runs.

Solutions

  1. Skip the default workspace in any cleanup loop: `if [ "$ws" != "default" ]; then tofu workspace delete "$ws"; fi`.
  2. Do not call DeleteWorkspace on "" - guard against empty names from upstream config.
  3. To 'reset' default state, run `tofu destroy` against it instead of deleting the workspace.

Example fix

# before
tofu workspace delete default
# after - reset state instead of deleting the workspace
tofu workspace select default
tofu destroy
Defensive patterns

Strategy: validation

Validate before calling

func deleteWorkspace(name string) error {
    if name == backend.DefaultStateName || name == "" {
        return fmt.Errorf("refusing to delete protected workspace %q; use `tofu destroy` to clear default state", name)
    }
    // ... proceed
}

Prevention

When it happens

Trigger: DeleteWorkspace(name, _) is called with name == "default" or name == "". Triggered by `tofu workspace delete default`, `tofa workspace select` paths that try to delete the active default, or tooling that iterates workspaces and tries to delete all of them including default.

Common situations: Cleanup script that deletes every workspace; CI teardown that calls `tofu workspace delete` on the default; misunderstanding that the default workspace is immutable-by-deletion.

Related errors


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

Appendix: source

Thrown at internal/backend/remote-state/pg/backend_state.go:48

	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			return nil, diags.Append(err)
		}
		result = append(result, name)
	}
	if err := rows.Err(); err != nil {
		return nil, diags.Append(err)
	}

	return result, diags
}

func (b *Backend) DeleteWorkspace(name string, _ bool) tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics

	if name == backend.DefaultStateName || name == "" {
		return diags.Append(fmt.Errorf("can't delete default state"))
	}

	query := `DELETE FROM %s.%s WHERE name = $1`
	_, err := b.db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName), name)
	if err != nil {
		return diags.Append(err)
	}

	return diags
}

func (b *Backend) StateMgr(name string) (statemgr.Full, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics

	// Build the state client
	var stateMgr statemgr.Full = &remote.State{
		Client: &RemoteClient{
			Client:     b.db,

View on GitHub (pinned to d32a084675)