wavetermdev/waveterm · warning

workspace already deleted %w

Error message

workspace already deleted %w

What it means

DeleteWorkspace detected the workspace record is already absent (wstore.ErrNotFound) yet still returns an error — a quirk: the code returns (true, "", err) meaning it was already deleted but with a descriptive error attached. The wrapped cause is the DB ErrNotFound.

Source

Thrown at pkg/wcore/workspace.go:124

			wsList = waveobj.WorkspaceList{}
		}
		ws.Color = WorkspaceColors[len(wsList)%len(WorkspaceColors)]
		updated = true
	}
	if updated {
		wstore.DBUpdate(ctx, ws)
	}
	return ws, updated, nil
}

// If force is true, it will delete even if workspace is named.
// If workspace is empty, it will be deleted, even if it is named.
// Returns true if workspace was deleted, false if it was not deleted.
func DeleteWorkspace(ctx context.Context, workspaceId string, force bool) (bool, string, error) {
	log.Printf("DeleteWorkspace %s\n", workspaceId)
	workspace, err := wstore.DBMustGet[*waveobj.Workspace](ctx, workspaceId)
	if err != nil && wstore.ErrNotFound == err {
		return true, "", fmt.Errorf("workspace already deleted %w", err)
	}
	// @jalileh list needs to be saved early on i assume
	workspaces, err := ListWorkspaces(ctx)
	if err != nil {
		return false, "", fmt.Errorf("error retrieving workspaceList: %w", err)
	}

	if workspace.Name != "" && workspace.Icon != "" && !force && len(workspace.TabIds) > 0 {
		log.Printf("Ignoring DeleteWorkspace for workspace %s as it is named\n", workspaceId)
		return false, "", nil
	}

	for _, tabId := range workspace.TabIds {
		log.Printf("deleting tab %s\n", tabId)
		_, err := DeleteTab(ctx, workspaceId, tabId, false)
		if err != nil {
			return false, "", fmt.Errorf("error closing tab: %w", err)
		}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Treat ErrNotFound-wrapped as already-deleted and ignore, or check existence with DBGet first before deleting
  2. Refresh the workspace list in the UI to drop the stale entry
  3. Guard DeleteWorkspace to skip ids no longer present

Example fix

// before
wasDeleted, _, err := DeleteWorkspace(ctx, wsId, false)
if err != nil { return err }
// after
wasDeleted, _, err := DeleteWorkspace(ctx, wsId, false)
if err != nil && strings.Contains(err.Error(), "already deleted") { err = nil }
Defensive patterns

Strategy: try-catch

Validate before calling

_, err := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)
if errors.Is(err, wstore.ErrNotFound) {
    return nil // already deleted, nothing to do
}

Try / catch

deleted, _, err := wcore.DeleteWorkspace(ctx, wsId, false)
if err != nil && strings.Contains(err.Error(), "already deleted") {
    return nil // idempotent success
}
if err != nil { return err }

Prevention

When it happens

Trigger: Calling DeleteWorkspace, SwitchWorkspace, or CloseWindow with a workspaceId whose row was already removed (double delete, deleted by another instance).

Common situations: Double-clicking delete; two windows deleting the same workspace; stale id after prior cleanup.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/bf24aa894c723d95. Report an issue: GitHub.