hashicorp/terraform · error

error deleting workspace

Error message

error deleting workspace %s: %v

What it means

remoteClient.Delete calls Workspaces.Delete — invoked when Terraform is asked to delete the workspace backing the remote state (e.g. `terraform workspace delete`). ErrResourceNotFound is tolerated (already gone); anything else is surfaced with the workspace name.

Solutions

  1. Delete the workspace's state and pending runs first (or use TFC UI which orchestrates this).
  2. Unlock the workspace if it is locked before retrying delete.
  3. Use a token with admin-level permission on the workspace.
  4. If already deleted out-of-band, the next attempt tolerates ErrResourceNotFound.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm workspace is empty/unlocked before delete
ws, _ := c.Workspaces.Read(ctx, org, name)
if ws.Locked { return fmt.Errorf("workspace %s is locked", name) }

Try / catch

// Tolerate 'already deleted' but surface real failures
if err := c.Workspaces.Delete(ctx, org, name); err != nil && err != tfe.ErrResourceNotFound {
    return err
}

Prevention

When it happens

Trigger: Workspaces.Delete fails: the workspace is not empty (still has state versions / runs), it is currently locked, the token lacks 'Admin' / 'Delete Workspaces' permission, 5xx, or network error.

Common situations: Trying to delete a workspace that still has state, runs in progress, or a lock; team token without admin scope; deleting from the CLI while a TFC run is queued; TFE maintenance window.

Related errors


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

Appendix: source

Thrown at internal/backend/remote/backend_state.go:167

	if errors.Is(err, tfe.ErrStateVersionUploadNotSupported) {
		// Create the new state with content included in the request (Terraform Enterprise v202306-1 and below)
		log.Println("[INFO] Detected that state version upload is not supported. Retrying using compatibility state upload.")
		return diags.Append(r.uploadStateFallback(ctx, stateFile, state, o))
	}
	if err != nil {
		r.stateUploadErr = true
		return diags.Append(fmt.Errorf("error uploading state: %v", err))
	}

	return nil
}

// Delete the remote state.
func (r *remoteClient) Delete() tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics
	err := r.client.Workspaces.Delete(context.Background(), r.organization, r.workspace.Name)
	if err != nil && err != tfe.ErrResourceNotFound {
		return diags.Append(fmt.Errorf("error deleting workspace %s: %v", r.workspace.Name, err))
	}

	return nil
}

// EnableForcePush to allow the remote client to overwrite state
// by implementing remote.ClientForcePusher
func (r *remoteClient) EnableForcePush() {
	r.forcePush = true
}

// Lock the remote state.
func (r *remoteClient) Lock(info *statemgr.LockInfo) (string, error) {
	ctx := context.Background()

	lockErr := &statemgr.LockError{Info: r.lockInfo}

	// Lock the workspace.

View on GitHub (pinned to d32a084675)